#lang scribble/doc @(require "mz.rkt") @title[#:tag "procedures"]{Procedures} @defproc[(procedure? [v any/c]) boolean]{ Returns @racket[#t] if @racket[v] is a procedure, @racket[#f] otherwise.} @defproc[(apply [proc procedure?] [v any/c] ... [lst list?] [#: kw-arg any/c] ...) any]{ @guideintro["apply"]{@racket[apply]} Applies @racket[proc] using the content of @racket[(list* v ... lst)] as the (by-position) arguments. The @racket[#: kw-arg] sequence is also supplied as keyword arguments to @racket[proc], where @racket[#:] stands for any keyword. The given @racket[proc] must accept as many arguments as the number of @racket[v]s plus length of @racket[lst], it must accept the supplied keyword arguments, and it must not require any other keyword arguments; otherwise, the @exnraise[exn:fail:contract]. The given @racket[proc] is called in tail position with respect to the @racket[apply] call. @mz-examples[ (apply + '(1 2 3)) (apply + 1 2 '(3)) (apply + '()) (apply sort (list (list '(2) '(1)) <) #:key car) ]} @deftogether[(@defproc[(compose [proc procedure?] ...) procedure?] @defproc[(compose1 [proc procedure?] ...) procedure?])]{ Returns a procedure that composes the given functions, applying the last @racket[proc] first and the first @racket[proc] last. The @racket[compose] function allows the given functions to consume and produce any number of values, as long as each function produces as many values as the preceding function consumes, while @racket[compose1] restricts the internal value passing to a single value. In both cases, the input arity of the last function and the output arity of the first are unrestricted, and they become the corresponding arity of the resulting composition (including keyword arguments for the input side). When no @racket[proc] arguments are given, the result is @racket[values]. When exactly one is given, it is returned. @mz-examples[ ((compose1 - sqrt) 10) ((compose1 sqrt -) 10) ((compose list split-path) (bytes->path #"/a" 'unix)) ] Note that in many cases, @racket[compose1] is preferred. For example, using @racket[compose] with two library functions may lead to problems when one function is extended to return two values, and the preceding one has an optional input with different semantics. In addition, @racket[compose1] may create faster compositions. } @defproc[(procedure-rename [proc procedure?] [name symbol?]) procedure?]{ Returns a procedure that is like @racket[proc], except that its name as returned by @racket[object-name] (and as printed for debugging) is @racket[name]. The given @racket[name] is used for printing an error message if the resulting procedure is applied to the wrong number of arguments. In addition, if @racket[proc] is an @tech{accessor} or @tech{mutator} produced by @racket[struct], @racket[make-struct-field-accessor], or @racket[make-struct-field-mutator], the resulting procedure also uses @racket[name] when its (first) argument has the wrong type. More typically, however, @racket[name] is not used for reporting errors, since the procedure name is typically hard-wired into an internal check.} @defproc[(procedure->method [proc procedure?]) procedure?]{ Returns a procedure that is like @racket[proc] except that, when applied to the wrong number of arguments, the resulting error hides the first argument as if the procedure had been compiled with the @indexed-racket['method-arity-error] syntax property.} @; ---------------------------------------- @section{Keywords and Arity} @defproc[(keyword-apply [proc procedure?] [kw-lst (listof keyword?)] [kw-val-lst list?] [v any/c] ... [lst list?] [#: kw-arg any/c] ...) any]{ @guideintro["apply"]{@racket[keyword-apply]} Like @racket[apply], but @racket[kw-lst] and @racket[kw-val-lst] supply by-keyword arguments in addition to the by-position arguments of the @racket[v]s and @racket[lst], and in addition to the directly supplied keyword arguments in the @racket[#: kw-arg] sequence, where @racket[#:] stands for any keyword. The given @racket[kw-lst] must be sorted using @racket[keyword], otherwise, the @exnraise[exn:fail:contract]. The given @racket[kw-val-lst] must have the same length as @racket[kw-lst], otherwise, the @exnraise[exn:fail:contract]. The given @racket[proc] must accept all of the keywords in @racket[kw-lst] plus the @racket[#:]s, it must not require any other keywords, and it must accept as many by-position arguments as supplied via the @racket[v]s and @racket[lst]; otherwise, the @exnraise[exn:fail:contract]. @defexamples[ (define (f x #:y y #:z [z 10]) (list x y z)) (keyword-apply f '(#:y) '(2) '(1)) (keyword-apply f '(#:y #:z) '(2 3) '(1)) (keyword-apply f #:z 7 '(#:y) '(2) '(1)) ]} @defproc[(procedure-arity [proc procedure?]) procedure-arity?]{ Returns information about the number of by-position arguments accepted by @racket[proc]. See also @racket[procedure-arity?].} @defproc[(procedure-arity? [v any/c]) boolean?]{ A valid arity @racket[_a] is one of the following: @itemize[ @item{An exact non-negative integer, which means that the procedure accepts @racket[_a] arguments, only.} @item{A @racket[arity-at-least] instance, which means that the procedure accepts @racket[(arity-at-least-value _a)] or more arguments.} @item{A list containing integers and @racket[arity-at-least] instances, which means that the procedure accepts any number of arguments that can match one of the elements of @racket[_a].} ] Generally, @racket[procedure-arity] always produces an arity that is normalized. Specifically, it is either the empty list (corresponding to the procedure @racket[(case-lambda)]), one of the first two cases above, or a list that contains at least two elements. If it is a list, there is at most one @racket[arity-at-least] instance that appears as the last element of the list, all of the other elements are sorted in ascending order, and there are no duplicate elements. @mz-examples[ (procedure-arity cons) (procedure-arity list) (arity-at-least? (procedure-arity list)) (arity-at-least-value (procedure-arity list)) (arity-at-least-value (procedure-arity (lambda (x . y) x))) (procedure-arity (case-lambda [(x) 0] [(x y) 1])) ]} @defproc[(procedure-arity-includes? [proc procedure?] [k exact-nonnegative-integer?] [kws-ok? any/c #f]) boolean?]{ Returns @racket[#t] if the procedure can accept @racket[k] by-position arguments, @racket[#f] otherwise. If @racket[kws-ok?] is @racket[#f], the result is @racket[#t] only if @racket[proc] has no required keyword arguments. @mz-examples[ (procedure-arity-includes? cons 2) (procedure-arity-includes? display 3) (procedure-arity-includes? (lambda (x #:y y) x) 1) (procedure-arity-includes? (lambda (x #:y y) x) 1 #t) ]} @defproc[(procedure-reduce-arity [proc procedure?] [arity procedure-arity?]) procedure?]{ Returns a procedure that is the same as @racket[proc] (including the same name returned by @racket[object-name]), but that accepts only arguments consistent with @racket[arity]. In particular, when @racket[procedure-arity] is applied to the generated procedure, it returns a value that is @racket[equal?] to @racket[arity]. If the @racket[arity] specification allows arguments that are not in @racket[(procedure-arity proc)], the @exnraise[exn:fail:contract]. If @racket[proc] accepts keyword argument, either the keyword arguments must be all optional (and they are not accepted in by the arity-reduced procedure) or @racket[arity] must be the empty list (which makes a procedure that cannot be called); otherwise, the @exnraise[exn:fail:contract]. @examples[ (define my+ (procedure-reduce-arity + 2)) (my+ 1 2) (my+ 1 2 3) ]} @defproc[(procedure-keywords [proc procedure?]) (values (listof keyword?) (or/c (listof keyword?) #f))]{ Returns information about the keyword arguments required and accepted by a procedure. The first result is a list of distinct keywords (sorted by @racket[keyword* . any)] [plain-proc procedure? (lambda args (apply proc null null args))]) procedure?]{ Returns a procedure that accepts all keyword arguments (without requiring any keyword arguments). When the procedure returned by @racket[make-keyword-procedure] is called with keyword arguments, then @racket[proc] is called; the first argument is a list of distinct keywords sorted by @racket[keywordvector args)))) (show2 1) (show2 #:init 0 1 2 3 #:extra 4) ]} @defproc[(procedure-reduce-keyword-arity [proc procedure?] [arity procedure-arity?] [required-kws (listof keyword?)] [allowed-kws (or/c (listof keyword?) #f)]) procedure?]{ Like @racket[procedure-reduce-arity], but constrains the keyword arguments according to @racket[required-kws] and @racket[allowed-kws], which must be sorted using @racket[keyword . any/c)] [v1 any/c] [v2 any/c]) any/c]{ Extracts a value from @racket[v] if it is an instance of @racket[type], which must have the property @racket[prop:checked-procedure]. If @racket[v] is such an instance, then the first field of @racket[v] is extracted and applied to @racket[v1] and @racket[v2]; if the result is a true value, the result is the value of the second field of @racket[v]. If @racket[v] is not an instance of @racket[type], or if the first field of @racket[v] applied to @racket[v1] and @racket[v2] produces @racket[#f], then @racket[proc] is applied to @racket[v], @racket[v1], and @racket[v2], and its result is returned by @racket[checked-procedure-check-and-extract].} @; ---------------------------------------------------------------------- @section{Reflecting on Primitives} A @idefterm{primitive procedure} is a built-in procedure that is implemented in low-level language. Not all procedures of @racketmodname[racket/base] are primitives, but many are. The distinction is mainly useful to other low-level code. @defproc[(primitive? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is a primitive procedure, @racket[#f] otherwise.} @defproc[(primitive-closure? [v any/c]) boolean]{ Returns @racket[#t] if @racket[v] is internally implemented as a primitive closure rather than a simple primitive procedure, @racket[#f] otherwise.} @defproc[(primitive-result-arity [prim primitive?]) procedure-arity?]{ Returns the arity of the result of the primitive procedure @racket[prim] (as opposed to the procedure's input arity as returned by @racket[procedure-arity]). For most primitives, this procedure returns @racket[1], since most primitives return a single value when applied.} @; ---------------------------------------- @section{Additional Higher-Order Functions} @note-lib[racket/function] @(define fun-eval (make-base-eval)) @(interaction-eval #:eval fun-eval (require racket/function)) @defproc[(identity [v any/c]) any/c]{ Returns @racket[v]. } @defproc[(const [v any]) procedure?]{ Returns a procedure that accepts any arguments (including keyword arguments) and returns @racket[v]. @mz-examples[#:eval fun-eval ((const 'foo) 1 2 3) ((const 'foo)) ]} @deftogether[(@defform[(thunk body ...+)] @defform[(thunk* body ...+)])]{ The @racket[thunk] form creates a nullary function that evaluates the given body. The @racket[thunk*] form is similar, except that the resulting function accepts any arguments (including keyword arguments). @defexamples[ #:eval fun-eval (define th1 (thunk (define x 1) (printf "~a\n" x))) (th1) (th1 'x) (th1 #:y 'z) (define th2 (thunk* (define x 1) (printf "~a\n" x))) (th2) (th2 'x) (th2 #:y 'z) ]} @defproc[(negate [proc procedure?]) procedure?]{ Returns a procedure that is just like @racket[proc], except that it returns the @racket[not] of @racket[proc]'s result. @mz-examples[#:eval fun-eval (filter (negate symbol?) '(1 a 2 b 3 c)) (map (negate =) '(1 2 3) '(1 1 1)) ]} @defproc*[([(curry [proc procedure?]) procedure?] [(curry [proc procedure?] [v any/c] ...+) any/c])]{ Returns a procedure that is a curried version of @racket[proc]. When the resulting procedure is first applied, unless it is given the maximum number of arguments that it can accept, the result is a procedure to accept additional arguments. @mz-examples[#:eval fun-eval ((curry list) 1 2) ((curry cons) 1) ((curry cons) 1 2) ] After the first application of the result of @racket[curry], each further application accumulates arguments until an acceptable number of arguments have been accumulated, at which point the original @racket[proc] is called. @mz-examples[#:eval fun-eval (((curry list) 1 2) 3) (((curry list) 1) 3) ((((curry foldl) +) 0) '(1 2 3)) ] A function call @racket[(curry proc v ...)] is equivalent to @racket[((curry proc) v ...)]. In other words, @racket[curry] itself is curried. The @racket[curry] function provides limited support for keyworded functions: only the @racket[curry] call itself can receive keyworded arguments to be propagated eventually to @racket[proc]. @mz-examples[#:eval fun-eval (map ((curry +) 10) '(1 2 3)) (map (curry + 10) '(1 2 3)) (map (compose (curry * 2) (curry + 10)) '(1 2 3)) (define foo (curry (lambda (x y z) (list x y z)))) (foo 1 2 3) (((((foo) 1) 2)) 3) ]} @defproc*[([(curryr [proc procedure?]) procedure?] [(curryr [proc procedure?] [v any/c] ...+) any/c])]{ Like @racket[curry], except that the arguments are collected in the opposite direction: the first step collects the rightmost group of arguments, and following steps add arguments to the left of these. @mz-examples[#:eval fun-eval (map (curryr list 'foo) '(1 2 3)) ]} @close-eval[fun-eval]