#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?]) any]{ @guideintro["apply"]{@scheme[apply]} Applies @scheme[proc] using the content of @scheme[(list* v ... lst)] as the (by-position) arguments. The given @scheme[proc] must accept as many arguments as the number of @scheme[v]s plus length of @scheme[lst], and it must not require any keyword arguments; otherwise, the @exnraise[exn:fail:contract]. The given @scheme[proc] is called in tail position with respect to the @scheme[apply] call. @examples[ (apply + '(1 2 3)) (apply + 1 2 '(3)) (apply + '()) ]} @; ---------------------------------------- @section{Keywords and Arity} @declare-exporting[(lib "scheme/procedure")] @defproc[(keyword-apply [proc procedure?] [kw-lst (listof keyword?)] [kw-val-lst list?] [v any/c] ... [lst list?]) 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]. The given @scheme[kw-lst] must be sorted using @scheme[keyword<], and no keyword can appear twice in @scheme[kw-lst], 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], 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)) ]} @defproc[(procedure-arity [proc procedure?]) arity?]{ Returns information about the number of by-position arguments accepted by @scheme[proc]. See also @scheme[arity?].} @defproc[(arity? [v any/c]) boolean?]{ A valid arity 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].} } @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. @examples[ (procedure-arity-includes? cons 2) (procedure-arity-includes? display 3) ]} @defproc[(procedure-reduce-arity [proc procedure?] [arity 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].} @defproc[(procedure-keywords [proc procedure?]) (values (listof keyword?) (or/c (listof keyword?) false/c))]{ Returns information about the keyword arguments required and accepted by a procedure. The first result is a list of keywords (sorted by @scheme[keyword<]) that are required when applying @scheme[proc]. The second result is a list of accepted keywords (sorted by @scheme[keyword<]), or @scheme[#f] to mean that any keyword is accepted. When the second result is a list, every element in the first list is also in the second list. @examples[ (procedure-keywords +) (procedure-keywords (lambda (#:tag t #:mode m) t)) (procedure-keywords (lambda (#:tag t #:mode [m #f]) t)) ]} @defproc[(make-keyword-procedure [proc (((listof keyword?) list?) list? . ->* . 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 result is called with keyword arguments, then @scheme[proc] is called; the first argument is a list of keywords sorted by @scheme[keyword<], the second argument is a parllel list containing a value for each keyword, and the remaining arguments are the by-position arguments. When the result is called without keyword arguments, then @scheme[plain-proc] is called. Furthermore, @scheme[procedure-arity] obtains its result frmo @scheme[plain-proc]. @defexamples[ (define show (make-keyword-procedure (lambda (kws kw-args . rest) (list kws kw-args rest)))) (show 1) (show #:init 0 1 2 3 #:extra 4) ]} @defstruct[arity-at-least ([value nonnegative-exact-integer?])]{ This structure type is used for the result of @scheme[procedure-arity]. See also @scheme[arity?].} @defthing[prop:procedure struct-type-property?]{ A @tech{structure type property} to indentify structure types whose instances can be applied as procedures. In particular, when @scheme[procedure?] is applied to the instance, the result will be @scheme[#t], and when an instance is used in the function position of an application expression, a procedure is extracted from the instance and used to complete the procedure call. If the @scheme[prop:procedure] property value is an integer, it designates a field within the structure that should contain a procedure. The integer must be between @scheme[0] (inclusive) and the number of non-automatic fields in the structure type (exclusive, not counting supertype fields). The designated field must also be specified as immutable, so that after an instance of the structure is created, its procedure cannot be changed. (Otherwise, the arity and name of the instance could change, and such mutations are generally not allowed for procedures.) When the instance is used as the procedure in an application expression, the value of the designated field in the instance is used to complete the procedure call. (This procedure can be another structure that acts as a procedure; the immutability of procedure fields disallows cycles in the procedure graph, so that the procedure call will eventually continue with a non-structure procedure.) That procedure receives all of the arguments from the application expression. The procedure's name (see @scheme[object-name]) and arity (see @scheme[procedure-arity]) are also used for the name and arity of the structure. If the value in the designated field is not a procedure, then the instance behaves like @scheme[(case-lambda)] (i.e., a procedure which does not accept any number of arguments). Providing an integer @scheme[proc-spec] argument to @scheme[make-struct-type] is the same as both supplying the value with the @scheme[prop:procedure] property and designating the field as immutable (so that a property binding or immutable designation is redundant and disallowed). @examples[ (define-struct annotated-proc (base note) #:property prop:procedure (struct-field-index base)) (define plus1 (make-annotated-proc (lambda (x) (+ x 1)) "adds 1 to its argument")) (procedure? plus1) (annotated-proc? plus1) (plus1 10) (annotated-proc-note plus1) ] When the @scheme[prop:procedure] value is a procedure, it should accept at least one argument. When an instance of the structure is used in an application expression, the property-value procedure is called with the instance as the first argument. The remaining arguments to the property-value procedure are the arguments from the application expression. Thus, if the application expression contained five arguments, the property-value procedure is called with six arguments. The name of the instance (see @scheme[object-name]) is unaffected by the property-value procedure, but the instance's arity is determined by subtracting one from every possible argument count of the property-value procedure. If the property-value procedure cannot accept at least one argument, then the instance behaves like @scheme[(case-lambda)]. Providing a procedure @scheme[proc-spec] argument to @scheme[make-struct-type] is the same as supplying the value with the @scheme[prop:procedure] property (so that a specific property binding is disallowed). @examples[ (define-struct fish (weight color) #:property prop:procedure (lambda (f n) (set-fish-weight! f (+ n (fish-weight f))))) (define wanda (make-fish 12 'red)) (fish? wanda) (procedure? wanda) (fish-weight wanda) (for-each wanda '(1 2 3)) (fish-weight wanda) ] If a structure type generates procedure instances, then subtypes of the type also generate procedure instances. The instances behave the same as instances of the original type. When a @scheme[prop:procedure] property or non-@scheme[#f] @scheme[proc-spec] is supplied to @scheme[make-struct-type] with a supertype that already behaves as a procedure, the @exnraise[exn:fail:contract].} @defproc[(procedure-struct-type? [type struct-type?]) boolean?]{ Returns @scheme[#t] if instances of the structure type represented by @scheme[type] are procedures (according to @scheme[procedure?]), @scheme[#f] otherwise.}