Lambda Expressions and Formal Parameters

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.

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.

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.

Required parameters

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.

Optional parameters

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.

Keyword parameters

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.

The following cause a match failure, unless there is a rest parameter:

There may not be extra non-keyword arguments (prefix or postfix)
beyond those matched by required and optional parameters.

There may not be any duplicated keyword arguments.

All keyowrds in the actual argument list must
match one of the keyword formal parameters.

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 does not accept keywords. In that case
the rest parameter will match any “postfix” 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.

Rest parameters

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):

If #!restrest-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.

If #!restrest-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 in object[]).

The generated method will be compiled like a Java varargs
methods if possible (i.e. no non-trivial patterns or keyword paremeters).

Using @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.

For @:rest-arg then rest-arg is a vector,
specifically an argvector. Keywords are allowed.

Guards (conditional expressions)

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.