Syntax to support optional and named keyword arguments.
let-optionals[*]
is originally from SCSH, and
let-keywords[*]
derived from Gauche.
Binding construct similar to let
. The var
s are
bound to fresh locations holding values taken in order from the
list ls
, body
is evaluated in the resulting
environment, and the value(s) of the last expression of body
returned. If the length of ls
is shorter than the number of
var
s, then the remaining var
s taken their values from
their corresponding default
s, evaluated in an unspecified
order. Unused default
s are not evaluated. If a final
rest
var is specified, then it is bound to any remaining
elements of ls
beyond the length of ls
, otherwise any
extra values are unused.
ls
is evaluated only once. It is an error if any
default
mutates ls
.
Typically used on the dotted rest list at the start of a lambda,
let-optionals
is more concise and more efficient than
case-lambda
for simple optional argument uses.
Example:
(define (copy-port . o)
(let-optionals o ((in (current-input-port))
(out (current-output-port))
(n-bytes #f))
(do ((i 0 (+ i 1))
(n (read-u8 in) (read-u8 in)))
((or (and n-bytes (>= i n-bytes))
(eof-object? b)))
(write-u8 b out)))
Example:
(let-optionals '(0) ((a 10) (b 11) (c 12))
(list a b c))
=> (0 11 12)
let*
equivalent to let-optionals
. Any required
default
values are evaluated in left-to-right order, with
all preceding var
s in scope.
Shorthand for
(lambda (required ... . o)
(let-optionals o ((var default) ... [rest])
body ...))
Variant of opt-lambda
which binds using
let-optionals*
.
Shorthand for
(define name (opt-lambda (var default) ... [rest]) body ...)
Shorthand for
(define name (opt-lambda* (var default) ... [rest]) body ...)
Search for the identifier key
in the list ls
, treating
it as a property list of the form (key1 val1 key2 val2
...)
, and return the associated val
. If not found, return
default
, or #f
.
Macro equivalent of keyword-ref
, where default
is
only evaluated if key
is not found.
Analogous to let-optionals
, except instead of binding the
var
s by position they are bound by name, by searching in
ls
with keyword-ref*
. If an optional keyword
argument is provided it must be an identifier to use as the name,
otherwise var
is used, appending a ":" (colon). If the name
is not found, var
is bound to default
, even if unused
names remain in ls
.
Keyword arguments have precedence in CommonLisp, DSSSL, and SRFI 89. However, unlike these systems you cannot mix optional and keyword arguments.
If an optional trailing identifier rest
is provided, it is
bound to the list of unused arguments not bound to any var
.
This is useful for chaining together keyword argument procedures -
you can extract just the arguments you need and pass on the rest
to another procedure. The rest
usage is similar to Python's
**args
(again predated by CommonLisp and DSSSL).
Note R7RS does not have a disjoint keyword type or auto-quoting syntax for keywords - they are simply identifiers (though no type checking is performed). Thus when passing keyword arguments they must be quoted (or otherwise dynamically evaluated).
Example:
(define (make-person . o)
(let-keywords o ((name "John Doe")
(age 0)
(occupation job: 'unemployed))
(vector name age occupation)))
(list (make-person)
(make-person 'name: "Methuselah" 'age: 969)
(make-person 'name: "Dr. Who" 'job: 'time-lord 'age: 1500))
ERROR on line 365 of file lib/chibi/doc.scm: immutable binding: make-person
Example:
(let-keywords '(b: 2 a: 1 other: 9)
((a 0) (b 0) (c 0) rest)
(list a b c rest))
=> (1 2 0 (other: 9))
Example:
(define (auth-wrapper proc)
(lambda o
(let-keywords o ((user #f)
(password #f)
rest)
(if (authenticate? user password)
(apply proc rest)
(error "access denied")))))
((auth-wrapper make-payment) 'user: "bob" 'password: "5ecret" 'amount: 50)
ERROR on line 365 of file lib/chibi/doc.scm: immutable binding: auth-wrapper
let*
equivalent to let-keywords
. Any required
default
values are evaluated in left-to-right order, with
all preceding var
s in scope.
Example:
(let-keywords* '(b: 5)
((a 1) (b (* a 2)) (c (* b 3)))
(list a b c))
=> (1 5 15)