#lang scribble/doc @(require "mz.ss") @title[#:tag "procedures"]{Procedures} @defproc[(procedure? [v any/c]) boolean]{ Returns @scheme[#t] if @scheme[v] is a procedure, @scheme[#f] otherwise.} @defproc[(apply [proc procedure?] [v any/c] ... [lst list?] [#: kw-arg any/c] ...) any]{ @guideintro["apply"]{@scheme[apply]} Applies @scheme[proc] using the content of @scheme[(list* v ... lst)] as the (by-position) arguments. The @scheme[#: kw-arg] sequence is also supplied as keyword arguments to @scheme[proc], where @scheme[#:] stands for any keyword. The given @scheme[proc] must accept as many arguments as the number of @scheme[v]s plus length of @scheme[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 @scheme[proc] is called in tail position with respect to the @scheme[apply] call. @mz-examples[ (apply + '(1 2 3)) (apply + 1 2 '(3)) (apply + '()) (apply sort (list (list '(2) '(1)) <) #:key car) ]} @defproc[(compose [proc procedure?] ...) procedure?]{ Returns a procedure that composes the given functions, applying the last @scheme[proc] first and the first @scheme[proc] last. The composed functions can consume and produce any number of values, as long as each function produces as many values as the preceding function consumes. When no @scheme[proc] arguments are given, the result is @scheme[values]. @mz-examples[ ((compose - sqrt) 10) ((compose sqrt -) 10) ((compose list split-path) (bytes->path #"/a" 'unix)) ]} @defproc[(procedure-rename [proc procedure?] [name symbol?]) procedure?]{ Returns a procedure that is like @scheme[proc], except that its name as returned by @scheme[object-name] (and as printed for debugging) is @scheme[name]. The given @scheme[name] is used for printing an error message if the resulting procedure is applied to the wrong number of arguments. In addition, if @scheme[proc] is an @tech{accessor} or @tech{mutator} produced by @scheme[struct], @scheme[make-struct-field-accessor], or @scheme[make-struct-field-mutator], the resulting procedure also uses @scheme[name] when its (first) argument has the wrong type. More typically, however, @scheme[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 @scheme[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-scheme['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"]{@scheme[keyword-apply]} Like @scheme[apply], but @scheme[kw-lst] and @scheme[kw-val-lst] supply by-keyword arguments in addition to the by-position arguments of the @scheme[v]s and @scheme[lst], and in addition to the directly supplied keyword arguments in the @scheme[#: kw-arg] sequence, where @scheme[#:] stands for any keyword. The given @scheme[kw-lst] must be sorted using @scheme[keyword], otherwise, the @exnraise[exn:fail:contract]. The given @scheme[kw-val-lst] must have the same length as @scheme[kw-lst], otherwise, the @exnraise[exn:fail:contract]. The given @scheme[proc] must accept all of the keywords in @scheme[kw-lst] plus the @scheme[#:]s, it must not require any other keywords, and it must accept as many by-position arguments as supplied via the @scheme[v]s and @scheme[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 @scheme[proc]. See also @scheme[procedure-arity?].} @defproc[(procedure-arity? [v any/c]) boolean?]{ A valid arity @scheme[_a] is one of the following: @itemize[ @item{An exact non-negative integer, which means that the procedure accepts @scheme[_a] arguments, only.} @item{A @scheme[arity-at-least] instance, which means that the procedure accepts @scheme[(arity-at-least-value _a)] or more arguments.} @item{A list containing integers and @scheme[arity-at-least] instances, which means that the procedure accepts any number of arguments that can match one of the elements of @scheme[_a].} ] Generally, @scheme[procedure-arity] always produces an arity that is normalized. Specifically, it is either the empty list (corresponding to the procedure @scheme[(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 @scheme[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?]) boolean?]{ Returns @scheme[#t] if the procedure can accept @scheme[k] arguments when no keyword arguments are supplied, @scheme[#f] otherwise. @mz-examples[ (procedure-arity-includes? cons 2) (procedure-arity-includes? display 3) ]} @defproc[(procedure-reduce-arity [proc procedure?] [arity procedure-arity?]) procedure?]{ Returns a procedure that is the same as @scheme[proc] (including the same name returned by @scheme[object-name]), but that accepts only arguments consistent with @scheme[arity]. In particular, when @scheme[procedure-arity] is applied to the generated procedure, it returns a value that is @scheme[equal?] to @scheme[arity]. If the @scheme[arity] specification allows arguments that are not in @scheme[(procedure-arity proc)], the @exnraise[exn:fail:contract]. If @scheme[proc] accepts keyword argument, either the keyword arguments must be all optional (and they are not accepted in by the arity-reduced procedure) or @scheme[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 keywords (sorted by @scheme[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). See also @scheme[procedure-reduce-keyword-arity]. When the result is called with keyword arguments, then @scheme[proc] is called; the first argument is a list of keywords sorted by @scheme[keyword . any/c)] [v1 any/c] [v2 any/c]) any/c]{ Extracts a value from @scheme[v] if it is an instance of @scheme[type], which must have the property @scheme[prop:checked-procedure]. If @scheme[v] is such an instance, then the first field of @scheme[v] is extracted and applied to @scheme[v1] and @scheme[v2]; if the result is a true value, the result is the value of the second field of @scheme[v]. If @scheme[v] is not an instance of @scheme[type], or if the first field of @scheme[v] applied to @scheme[v1] and @scheme[v2] produces @scheme[#f], then @scheme[proc] is applied to @scheme[v], @scheme[v1], and @scheme[v2], and its result is returned by @scheme[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 @schememodname[racket/base] are primitives, but many are. The distinction is mainly useful to other low-level code. @defproc[(primitive? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v] is a primitive procedure, @scheme[#f] otherwise.} @defproc[(primitive-closure? [v any/c]) boolean]{ Returns @scheme[#t] if @scheme[v] is internally implemented as a primitive closure rather than a simple primitive procedure, @scheme[#f] otherwise.} @defproc[(primitive-result-arity [prim primitive?]) procedure-arity?]{ Returns the arity of the result of the primitive procedure @scheme[prim] (as opposed to the procedure's input arity as returned by @scheme[procedure-arity]). For most primitives, this procedure returns @scheme[1], since most primitives return a single value when applied.} @; ---------------------------------------- @section{Additional Procedure Functions} @note-lib[racket/function] @(define fun-eval (make-base-eval)) @(interaction-eval #:eval fun-eval (require racket/function)) @defproc[(const [v any]) procedure?]{ Returns a procedure that accepts any arguments and returns @scheme[v]. @mz-examples[#:eval fun-eval ((const 'foo) 1 2 3) ((const 'foo)) ]} @defproc[(negate [proc procedure?]) procedure?]{ Returns a procedure that is just like @scheme[proc], except that it returns the @scheme[not] of @scheme[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 @scheme[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 @scheme[curry], each further application accumulates arguments until an acceptable number of arguments have been accumulated, at which point the original @scheme[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 @scheme[(curry proc v ...)] is equivalent to @scheme[((curry proc) v ...)]. In other words, @scheme[curry] itself is curried. The @scheme[curry] function provides limited support for keyworded functions: only the @scheme[curry] call itself can receive keyworded arguments to be propagated eventually to @scheme[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 @scheme[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]