108 lines
4.3 KiB
Racket
108 lines
4.3 KiB
Racket
#lang scribble/manual
|
|
|
|
@(require scribble/example racket/sandbox
|
|
(for-label typed/racket/base typed-compose))
|
|
|
|
@title{Utilities for composing functions in Typed Racket}
|
|
|
|
@author[@author+email["Sergiu Ivanov" "sivanov@colimite.fr"]]
|
|
|
|
@defmodule[typed-compose]
|
|
|
|
Typed Racket's @racket[compose] only takes two arguments, because in general it
|
|
is difficult to specify that the return types and the argument types should be
|
|
the same for two successive functions in the argument list. This package
|
|
defines some further utilities to allow @racket[compose]-ing more than two
|
|
functions more comfortable in Typed Racket.
|
|
|
|
@(define typed-compose-evaluator
|
|
(parameterize ([sandbox-output 'string]
|
|
[sandbox-error-output 'string]
|
|
[sandbox-memory-limit 50])
|
|
(make-evaluator 'typed/racket/base #:requires '(typed-compose))))
|
|
|
|
@section{License}
|
|
|
|
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
|
|
@bold{without any warranty}; without even the implied warranty of
|
|
@bold{merchantability} or @bold{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
|
|
@hyperlink["https://www.gnu.org/licenses/"]{https://www.gnu.org/licenses/}.
|
|
|
|
@section{Functions for composing functions}
|
|
|
|
@defproc[(compose-n [proc (-> a a)] ...) (-> a a)]{
|
|
|
|
Compose an arbitrary number of functions of type @racket[(-> a a)].
|
|
|
|
@examples[#:eval typed-compose-evaluator
|
|
((compose-n add1 add1 add1) 3)
|
|
]}
|
|
|
|
@defproc*[([(compose-3 [proc1 (-> c d)] [proc2 (-> b c)] [proc3 (-> a b)]) (-> a d)]
|
|
[(compose-4 [proc1 (-> d e)] [proc2 (-> c d)] [proc3 (-> b c)] [proc4 (-> a b)]) (-> a e)]
|
|
[(compose-5 [proc1 (-> e f)] [proc2 (-> d e)] [proc3 (-> c d)] [proc4 (-> b c)] [proc5 (-> a b)]) (-> a f)]
|
|
[(compose-6 [proc1 (-> f g)] [proc2 (-> e f)] [proc3 (-> d e)] [proc4 (-> c d)] [proc5 (-> b c)] [proc6 (-> a b)]) (-> a g)]
|
|
[(compose-7 [proc1 (-> g h)] [proc2 (-> f g)] [proc3 (-> e f)] [proc4 (-> d e)] [proc5 (-> c d)] [proc6 (-> b c)] [proc7 (-> a b)]) (-> a h)]
|
|
[(compose-8 [proc1 (-> h i)] [proc2 (-> g h)] [proc3 (-> f g)] [proc4 (-> e f)] [proc5 (-> d e)] [proc6 (-> c d)] [proc7 (-> b c)] [proc8 (-> a b)]) (-> a i)]
|
|
[(compose-9 [proc1 (-> i j)] [proc2 (-> h i)] [proc3 (-> g h)] [proc4 (-> f g)] [proc5 (-> e f)] [proc6 (-> d e)] [proc7 (-> c d)] [proc8 (-> b c)] [proc9 (-> a b)]) (-> a j)])]{
|
|
|
|
@racket[compose-i] composes @racket[i] functions. The rightmost function is
|
|
applied first.
|
|
|
|
@examples[#:eval typed-compose-evaluator
|
|
(define (s->n [x : String]) (cast (string->number x) Number))
|
|
(define fancy-add1 (compose-3 print add1 s->n))
|
|
fancy-add1
|
|
(fancy-add1 "1")
|
|
]}
|
|
|
|
@section{Macros for composing functions}
|
|
|
|
@defform[(make-compose n)
|
|
#:contracts ([n exact-nonnegative-integer])]{
|
|
|
|
Expants to a typed @racket[lambda] form composing exactly @racket[n]
|
|
one-argument functions. For example, @racket[compose-3] is defined as:
|
|
@racket[(define compose-3 (make-compose 3))]. The rest of the functions of the
|
|
@racket[compose-i] family are defined using this macro as well.
|
|
|
|
}
|
|
|
|
@defform[(multi-compose func ...)
|
|
#:contracts ([func expression])]{
|
|
|
|
Expands to a code applying @racket[compose] in a pairwise manner to the given
|
|
expressions. For example, @racket[(multi-compose f1 f2 f3 f4)] expands to
|
|
@racket[(compose f1 (compose f2 (compose f3 f4)))].
|
|
|
|
@examples[#:eval typed-compose-evaluator
|
|
((multi-compose add1
|
|
(λ ([x : Number]) (* x 3))
|
|
add1
|
|
(λ ([x : Number]) (+ x 2)))
|
|
3)
|
|
]}
|
|
|
|
@defform[(multi-chain func ...)
|
|
#:contracts ([func expression])]{
|
|
|
|
Like @racket[multi-compose], but the first function in the argument list is
|
|
applied first instead of last. For example, @racket[(multi-chain f1 f2 f3
|
|
f4)] expands to @racket[(compose f4 (compose f3 (compose f2 f1)))].
|
|
|
|
@examples[#:eval typed-compose-evaluator
|
|
(define f1 (λ ([x : Number]) (displayln "f1") (+ x 1)))
|
|
(define f2 (λ ([x : Number]) (displayln "f2") (+ x 1)))
|
|
(define f3 (λ ([x : Number]) (displayln "f3") (+ x 1)))
|
|
((multi-chain f1 f2 f3) 3)
|
|
((multi-compose f1 f2 f3) 3)
|
|
]}
|