The formal arguments list of a lambda expression has some extensions over standard Scheme: Kawa borrows the extended formal argument list of DSSSL, and Kawa 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
)
return-type
::=
type
opt-return-type
::=
[::
type
]
where
formals
::=
(
formal-arguments
)
| rest-arg
You can of course also use the extended format in a define
:
(define (name
formal-arguments
) [rtype
]body
)
formal-arguments
::=
required-or-guard
* [#!optional
optional-arg
...] (rest-key-args
| .
rest-arg
)
required-or-guard
::=
required-arg
|guard
rest-key-args
::=
[#!rest
rest-arg
] [#!key
key-arg
...]
| [#!key
key-arg
...] [#!rest
rest-arg
]
required-arg
::=
pattern
[::
type
]
| (
pattern
::
type
)
optional-arg
::=
variable
[::
type
]
| (
pattern
[::
type
] [initializer
[supplied-var
]])
supplied-var
::=
variable
key-arg
::=
variable
[::
type
]
| (
variable
[::
type
] [initializer
[supplied-var
]] )
rest-arg
::=
variable
When the procedure is applied to a list of actual arguments, the formal and actual arguments are processed from left to right as follows:
The required-arg
s are matched against actual (pre-keyword) arguments
in order, starting with the first actual argument.
A guard
is evaluated when it appears:
If it evaluates to false, then matching fails.
It shall be an error if there are fewer pre-keyword
arguments then there are req-arg
s.
Next the optional-arg
s are bound to remaining pre-keyword arguments.
If there are fewer remaining pre-keyword arguments than there are
optional-arg
s, then the remaining variable
s 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.
If there is a rest-arg
, it is bound to a list of all the
remaining actual arguments. These remaining actual arguments are also
eligible to be bound to keyword arguments. If there is no
rest-arg
and there are no key-arg
s, then it shall
be an error if there are any remaining actual arguments.
If #!key
was specified, then there shall be an even number of
remaining actual arguments. These are interpreted as a series of pairs,
where the first member of each pair is a keyword specifying the argument name,
and the second is the corresponding value. It shall be an error if the first
member of a pair is not a keyword. It shall be an error if the argument name
is not the same as a variable in a key-arg
s, unless there
is a rest-arg
. If the same argument name occurs more than once
in the list of actual arguments, then the first value is used.
If there is no actual argument for a particular key-arg
,
then the variable is bound
to the corresponding initializer
, if one was specified, and
otherwise to #f
. The initializer
is evaluated in an
environment in which all the previous formal parameters have been bound.
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.
If rtype
(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 specifies the
function’s return type. It is syntactic sugar for
(as <TYPE> (begin BODY))
.
You can set the properties
of the resulting procedure using an option-pair
. For example,
to set the setter
property of a procedure
to my-set-car
do the following:
(define my-car (lambda (arg) setter: my-set-car (primitive-car arg)))