Next: Procedure properties, Previous: Application and Arguments Lists, Up: Procedures [Contents][Index]
A lambda
expression evaluates to a procedure.
The environment in effect when the lambda
expression was
evaluated is remembered as part of the procedure. When
the procedure is later called with some actual arguments,
the environment in which the lambda
expression was evaluated
will be extended by binding the variables in the formal
argument list to fresh locations, and the corresponding actual
argument values will be stored in those locations.
(A fresh location is one that is distinct from every previously
existing location.) Next, the expressions in the body of the
lambda expression will be evaluated
sequentially in the extended environment. The results of
the last expression in the body will be returned as the results
of the procedure call.
(lambda (x) (+ x x)) ⇒ a procedure ((lambda (x) (+ x x)) 4) ⇒ 8 (define reverse-subtract (lambda (x y) (- y x))) (reverse-subtract 7 10) ⇒ 3 (define add4 (let ((x 4)) (lambda (y) (+ x y)))) (add4 6) ⇒ 10
The formal arguments list of a lambda expression has some extensions over standard Scheme: Kawa borrows the extended formal argument list of DSSSL, and allows you to declare the type of the parameter. More generally, you can use patterns.
lambda-expression ::=(lambda
formals option-pair* opt-return-type body)
opt-return-type ::= [::
type] formals ::=(
formal-arguments)
| rest-arg
An opt-return-type specifies the return type of the procedure: The result of evaluating the body is coerced to the specified type.
Deprecated: If the first form of the function body is an unbound
identifier of the form <TYPE>
(that is the first character
is ‘<’ and the last is ‘>’), then that is another way to specify the
function’s return type.
See properties for how to set and use an option-pair.
The define
form has a short-hand that combines
a lambda definition with binding the lambda to a variable:
(define (name formal-arguments) opt-return-type body)
formal-arguments ::= required-or-guard* [#!optional
optional-arg ...] rest-key-args rest-key-args ::= [#!rest
rest-arg] [#!key
key-arg ...] [guard] | [#!key
key-arg ...] [rest-parameter] [guard] |.
rest-arg
When the procedure is applied to an argument list, the latter is matched against formal parameters. This may involve some complex rules and pattern matching.
required-or-guard ::= required-arg | guard required-arg ::= pattern |(
pattern annotation-or-type*)
annotation-or-type ::= annotation |::
type
The required-args are matched against the actual (pre-keyword) arguments in order, starting with the first actual argument. It is an error if there are fewer pre-keyword arguments then there are required-args. While a pattern is most commonly an identifier, more complicated patterns are possible, thus more (or fewer) variables may be bound than there are arguments.
Note a pattern may include an opt-type-specifier. For example:
(define (isquare x::integer) (* x x))
In this case the actual argument is coerced to an integer
and then the result matched against the pattern x
.
This is how parameter types are specified.
The pattern may be enclosed in parentheses for clarify (just like for optional parameters), but in that case the type specifier is required to avoid ambiguity.
optional-arg ::= variable opt-type-specifier |(
pattern opt-type-specifier [initializer [supplied-var]])
supplied-var ::= variable
Next the optional-args are bound to remaining pre-keyword arguments.
If there are fewer remaining pre-keyword arguments than there are
optional-args, then the remaining variables are bound
to the corresponding initializer.
If no initializer was specified, it defaults to #f
.
(TODO: If a type is specified the default for initializer
is the default value of the type.)
The initializer is evaluated in an
environment in which all the previous formal parameters have been bound.
If a supplied-var is specified, it has type boolean,
and is set to true if there was an actual corresponding argument,
and false if the initializer was evaluated.
key-arg ::= variable opt-type-specifier |(
variable opt-type-specifier [initializer [supplied-var]])
Keyword parameters follow #!key
.
For each variable
if there is an actual keyword parameter whose keyword matches variable,
then variable is bound to the corresponding value.
If there is no matching artual argument, then the initializer is
evaluated and bound to the argument.
If initializer is not specified, it defaults to #f
.
The initializer is evaluated in an
environment in which all the previous formal parameters have been bound.
(define (fun x #!key (foo 1) (bar 2) (baz 3)) (list x foo bar baz)) (fun 9 baz: 10 foo: 11) ⇒ (9 11 2 10)
The following cause a match failure, unless there is a rest parameter:
It is not recommended to use both keyword parameters and a rest parameter that can match keyword arguments. Currently, the rest parameter will include any arguments that match the explicit keyword parameters, as well any that don’t, though this may change.
On the other hand, it is fine to have both keyword parameters and a rest parameter that does not accept keywords. In that case the rest parameter will match any “postfix” arguments:
#|kawa:8|# (define (fun x #!key k1 k2 #!rest r) (format "x:~w k1:~w k2:~w r:~w" x k1 k2 r)) (fun 3 k2: 12 100 101) ⇒ x:3 k1:#f k2:12 r:(100 101)
The supplied-var argument is as for optional arguments.
Performance note: Keyword parameters are implemented very efficiently and compactly when explicit in the code. The parameters are sorted by the compiler, and the actual keyword arguemnts at the call state are also sorted at compile-time. So keyword matching just requires a fast linear scan comparing the two sorted lists. This implementation is also very compact, compared to say a hash table.
If a type is specified, the corresponding actual argument (or the initializer default value) is coerced to the specified type. In the function body, the parameter has the specified type.
A “rest parameter” matches any arguments not matched by other parameters. You can write it using any of the following ways:
In addition, if formals is just a rest-arg identifier,
or a formal-arguments ends with . rest-arg
(i.e. is a dotted list) that is equivalent to using #!rest
.
These forms are similar but differ in the type of the rest-arg and whether keywords are allowed (as part of the rest-arg):
#!rest
rest-arg is used with no type specifier
(or a type specifier of list
)
then rest-arg is a list.
Keywords are not allowed if #!key
has been seen.
(For backward compatibility, it is allowed to have extra keywords
if #!rest
is followed by !key
.)
If there are any keywords, then rest-arg is more specifically
an arglist
.
#!rest
rest-arg is used with type specifier
that is a Java array (for example #!rest r::string[]
then rest-arg has that type. Each argument must be compatible
with the element type of the array.
Keywords are not allowed (even if type is object[]
).
The generated method will be compiled like a Java varargs method if possible (i.e. no non-trivial patterns or keyword paremeters).
@
rest-arg is equivalent to
#!rest rest-arg::object[]
:
Keywords are not allowed; the type of rest-arg is a Java array;
the method is compiled like a Java varargs method.
@:
rest-arg then rest-arg is a vector,
specifically an argvector
. Keywords are allowed.
A guard is evaluated when it appears in the formal parameter list. If it evaluates to false, then matching fails. Guards can appears before or after required arguments, or at the very end, after all other formal parameters.
Next: Procedure properties, Previous: Application and Arguments Lists, Up: Procedures [Contents][Index]