typed-compose/typed-compose.rkt

162 lines
5.2 KiB
Racket
Raw Normal View History

;;; typed-compose.rkt
;;;
;;; Copyright 2020 Sergiu Ivanov <sivanov@colimite.fr>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation, either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see
;;; <https://www.gnu.org/licenses/>.
2020-12-17 20:45:26 +01:00
#lang typed/racket
(require (for-syntax syntax/parse))
(module+ test
(require typed/rackunit))
2020-12-18 11:43:17 +01:00
2020-12-18 13:04:07 +01:00
(provide compose-n
compose-3 compose-4 compose-5 compose-6 compose-7 compose-8 compose-9
2020-12-20 20:45:29 +01:00
multi-compose multi-chain)
2020-12-18 13:04:07 +01:00
2020-12-18 11:43:17 +01:00
(: compose-n (All (a) (-> (-> a a) * (-> a a))))
(define (compose-n . funcs)
(λ (x)
(for/foldr ([x x]) ([f funcs])
(f x))))
(module+ test
(check-equal? ((compose-n add1 add1 add1) 3) 6))
2020-12-18 12:55:06 +01:00
(: compose-3 (All (a b c d)
(-> (-> c d)
(-> b c)
(-> a b)
(-> a d))))
(define (compose-3 f1 f2 f3)
(λ (x) (f1 (f2 (f3 x)))))
(: compose-4 (All (a b c d e)
(-> (-> d e)
(-> c d)
(-> b c)
(-> a b)
(-> a e))))
(define (compose-4 f1 f2 f3 f4)
(λ (x) (f1 (f2 (f3 (f4 x))))))
(: compose-5 (All (a b c d e f)
(-> (-> e f)
(-> d e)
(-> c d)
(-> b c)
(-> a b)
(-> a f))))
(define (compose-5 f1 f2 f3 f4 f5)
(λ (x) (f1 (f2 (f3 (f4 (f5 x)))))))
(: compose-6 (All (a b c d e f g)
(-> (-> f g)
(-> e f)
(-> d e)
(-> c d)
(-> b c)
(-> a b)
(-> a g))))
(define (compose-6 f1 f2 f3 f4 f5 f6)
(λ (x) (f1 (f2 (f3 (f4 (f5 (f6 x))))))))
(: compose-7 (All (a b c d e f g h)
(-> (-> g h)
(-> f g)
(-> e f)
(-> d e)
(-> c d)
(-> b c)
(-> a b)
(-> a h))))
(define (compose-7 f1 f2 f3 f4 f5 f6 f7)
(λ (x) (f1 (f2 (f3 (f4 (f5 (f6 (f7 x)))))))))
(: compose-8 (All (a b c d e f g h i)
(-> (-> h i)
(-> g h)
(-> f g)
(-> e f)
(-> d e)
(-> c d)
(-> b c)
(-> a b)
(-> a i))))
(define (compose-8 f1 f2 f3 f4 f5 f6 f7 f8)
(λ (x) (f1 (f2 (f3 (f4 (f5 (f6 (f7 (f8 x))))))))))
(: compose-9 (All (a b c d e f g h i j)
(-> (-> i j)
(-> h i)
(-> g h)
(-> f g)
(-> e f)
(-> d e)
(-> c d)
(-> b c)
(-> a b)
(-> a j))))
(define (compose-9 f1 f2 f3 f4 f5 f6 f7 f8 f9)
(λ (x) (f1 (f2 (f3 (f4 (f5 (f6 (f7 (f8 (f9 x)))))))))))
(module+ test
(define (s->n [s : String]) (cast (string->number s) Number))
(define (n->s [n : Number]) (number->string n))
(check-equal? ((compose-3 n->s add1 s->n) "3") "4")
(check-equal? ((compose-4 n->s add1 add1 s->n) "3") "5")
(check-equal? ((compose-5 n->s add1 add1 add1 s->n) "3") "6")
(check-equal? ((compose-6 n->s add1 add1 add1 add1 s->n) "3") "7")
(check-equal? ((compose-7 n->s add1 add1 add1 add1 add1 s->n) "3") "8")
(check-equal?
((compose-8 n->s add1 add1 add1 add1 add1 add1 s->n) "3") "9")
(check-equal?
((compose-9 n->s add1 add1 add1 add1 add1 add1 add1 s->n) "3") "10"))
2020-12-18 12:58:43 +01:00
(define-syntax (multi-compose stx)
;; Implementation by Sorawee Porncharoenwase.
(syntax-parse stx
[(_ f:expr g:expr)
#'(compose f g)]
[(_ f:expr funcs:expr ...)
#'(compose f (multi-compose funcs ...))]))
(module+ test
(check-equal? ((multi-compose add1
(λ ([x : Number]) (* x 3))
add1
(λ ([x : Number]) (+ x 2)))
3)
19))
2020-12-20 20:45:29 +01:00
(define-syntax (multi-chain stx)
(syntax-parse stx
[(_ funcs:expr ...)
(define rev-funcs (reverse (syntax->list #'(funcs ...))))
#`(multi-compose #,@rev-funcs)]))
(module+ test
(test-case "multi-chain and multi-compose"
(define f1 (λ ([x : Number]) (displayln "f1") (+ x 1)))
(define f2 (λ ([x : Number]) (displayln "f2") (+ x 1)))
(define f3 (λ ([x : Number]) (displayln "f3") (+ x 1)))
(check-equal?
(with-output-to-string (λ () (displayln ((multi-chain f1 f2 f3) 3))))
"f1\nf2\nf3\n6\n")
(check-equal?
(with-output-to-string (λ () (displayln ((multi-compose f1 f2 f3) 3))))
"f3\nf2\nf1\n6\n")))