3.8 Procedure Expressions: lambda and case-lambda (original) (raw)
3.8 Procedure Expressions: lambda and case-lambda🔗ℹ
Functions: lambda in The Racket Guide introduces procedure expressions.
(lambda kw-formals body ...+) (λ kw-formals body ...+) kw-formals = (arg ...) | (arg ...+ . rest-id) rest-id arg = id [id default-expr] keyword id keyword [id default-expr]
Produces a procedure. The kw-formals determines the number of arguments and which keyword arguments that the procedure accepts.
Considering only the first arg case, a simplekw-formals has one of the following three forms:
The procedure accepts as many non-keyword argument values as the number of ids. Each idis associated with an argument value by position.
The procedure accepts any number of non-keyword arguments greater or equal to the number ofids. When the procedure is applied, the ids are associated with argument values by position, and all leftover arguments are placed into a list that is associated torest-id.
The procedure accepts any number of non-keyword arguments. All arguments are placed into a list that is associated with rest-id.
More generally, an arg can include a keyword and/or default value. Thus, the first two cases above are more completely specified as follows:
Each arg has the following four forms:
Adds one to both the minimum and maximum number of non-keyword arguments accepted by the procedure. Theid is associated with an actual argument by position.
Adds one to the maximum number of non-keyword arguments accepted by the procedure. Theid is associated with an actual argument by position, and if no such argument is provided, the default-expris evaluated to produce a value associated with id. No arg with a default-expr can appear before an id without a default-expr and without a keyword.
The procedure requires a keyword-based argument using keyword. The idis associated with a keyword-based actual argument usingkeyword.
keyword [id default-expr]
The procedure accepts a keyword-based argument using keyword. Theid is associated with a keyword-based actual argument using keyword, if supplied in an application; otherwise, the default-expr is evaluated to obtain a value to associate with id.
The position of a keyword arg inkw-formals does not matter, but each specifiedkeyword must be distinct.
Like the previous case, but the procedure accepts any number of non-keyword arguments beyond its minimum number of arguments. When more arguments are provided than non-keyword arguments among theargs, the extra arguments are placed into a list that is associated to rest-id.
In other words, argument bindings with default-value expressions are evaluated analogous to let*.
The kw-formals identifiers are bound in thebodys. When the procedure is applied, a new locationis created for each identifier, and the location is filled with the associated argument value. The locations are created and filled in order, with default-exprs evaluated as needed to fill locations.
If any identifier appears in the bodys that is not one of the identifiers in kw-formals, then it refers to the same location that it would if it appeared in place of the lambdaexpression. (In other words, variable reference is lexically scoped.)
When multiple identifiers appear in a kw-formals, they must be distinct according to bound-identifier=?.
If the procedure produced by lambda is applied to fewer or more by-position or by-keyword arguments than it accepts, to by-keyword arguments that it does not accept, or without required by-keyword arguments, then the exn:fail:contract exception is raised.
The last body expression is in tail position with respect to the procedure body.
Examples:
> ((lambda (x) x) 10) 10 > ((lambda (x y) (list y x)) 1 2) '(2 1) > ((lambda (x [y 5]) (list y x)) 1 2) '(2 1) > (let ([f (lambda (x #:arg y) (list y x))]) (list (f 1 #:arg 2) (f #:arg 2 1))) '((2 1) (2 1))
When compiling a lambda or case-lambda expression, Racket looks for a 'method-arity-error property attached to the expression (see Syntax Object Properties). If it is present with a true value, and if no case of the procedure accepts zero arguments, then the procedure is marked so that anexn:fail:contract:arity exception involving the procedure will hide the first argument, if one was provided. (Hiding the first argument is useful when the procedure implements a method, where the first argument is implicit in the original source). The property affects only the format of exn:fail:contract:arityexceptions, not the result of procedure-arity.
When a keyword-accepting procedure is bound to an identifier in certain ways, and when the identifier is used in the function position of an application form, then the application form may be expanded in such a way that the original binding is obscured as the target of the application. To help expose the connection between the function application and function declaration, an identifier in the expansion of the function application is tagged with a syntax propertyaccessible via syntax-procedure-alias-property if it is effectively an alias for the original identifier. An identifier in the expansion is tagged with asyntax property accessible via syntax-procedure-converted-arguments-property if it is like the original identifier except that the arguments are converted to a flattened form: keyword arguments, required by-position arguments, by-position optional arguments, and rest arguments—all as required, by-position arguments; the keyword arguments are sorted by keyword name, each optional keyword argument is followed by a boolean to indicate whether a value is provided, and #f is used for an optional keyword argument whose value is not provided; optional by-position arguments include #f for each non-provided argument, and then the sequence of optional-argument values is followed by a parallel sequence of booleans to indicate whether each optional-argument value was provided.
Changed in version 8.13.0.5 of package base: Adjusted binding so that (free-identifier=? #'λ #'lambda) produces#t.
(case-lambda [formals body ...+] ...) (case-λ [formals body ...+] ...) formals = (id ...) | (id ...+ . rest-id) rest-id
Produces a procedure. Each [formals body ...+]clause is analogous to a single lambda procedure; applying the case-lambda-generated procedure is the same as applying a procedure that corresponds to one of the clauses—the first procedure that accepts the given number of arguments. If no corresponding procedure accepts the given number of arguments, theexn:fail:contract exception is raised.
Note that a case-lambda clause supports onlyformals, not the more general kw-formals oflambda. That is, case-lambda does not directly support keyword and optional arguments.
Example:
> (let ([f (case-lambda [() 10] [(x) x] [(x y) (list y x)] [r r])]) (list (f) (f 1) (f 1 2) (f 1 2 3))) '(10 1 (2 1) (1 2 3))
Changed in version 8.13.0.5 of package base: Added case-λ.
(#%plain-lambda formals body ...+)
Like lambda, but without support for keyword or optional arguments.