When a procedure is called, the actual argument expression are evaluated, and the resulting values becomes the actual argument list. This is then matched against the formal parameter list (in the procedure definition), and assuming they match, the procedure body is called.
An argument list has three parts:
Zero or more prefix arguments, each of which is a value. These typically get bound to named required or optional formal parameters, but can also get bound to patterns.
Zero or more keyword arguments, each of which is a keyword (an identifier specified with keyword syntax) combined with a value. These are bound to either named keyword formal parameters, or bundled in with a rest parameter.
Zero or more postfix arguments, each of which is a value. These are usually bound to a “rest” formal parameter, which receives any remaining arguments.
If there are no keyword arguments, then it ambiguous where prefix arguments and and where postfix arguments start. This is normally not a problem: the called procedure can split them up however it wishes.
Note that all keyword arguments have to be grouped together: It is not allowed to have a keyword argument followed by a plain argument followed by a keyword argument.
The argument list is constructed by evaluating the each operand
of the procedure-call in order:
expression
The expression is evaluated, yielding a single value
that becomes a prefix or postfix argument.
keyword expression
The expression is evaluated. The resulting value combined
with the keyword becomes a keyword argument.
@expression
The expression is evaluated.
The result must be a sequence - a list, vector, or primitive array.
The values of the sequence are appended to the resulting argument list.
Keyword arguments are not allowed.
@:expression
The expression is evaluted.
The result can be a sequence;
a hash table (viewed as a collection of (keyword,value) pairs);
or an explicit argument list object, which is a sequence of values
or keyword arguments.
The values and keyword arguments
are appended to the resulting argument list, though subject to the restriction
that keyword arguments must be adjacent in the resulting argument list.
Sometimes it is useful to create an argument list out of pieces, take argument lists apart, iterate over them, and generally treat an argument list as an actual first-class value.
Explicit argument list objects can take multiple forms. The simplest is a sequence: a list, vector, or primitive array. Each element of the list becomes a value in the resulting argument list.
(define v1 '(a b c))
(define v2 (int[] 10 11 12 13))
(list "X" @v1 "Y" @v2 "Z")
⇒ ("X" a b c "Y" 10 11 12 13 "Z")
Things get more complicated once keywords are involved.
An explicit argument list with keywords is only allowed
when using the @: splicing form,
not the @ form. It can be either
a hash table (anything the implement java.util.Map
or the types arglist or argvector.
Design note: An argument list with keywords is straightforward in Common Lisp and some Scheme implementations (including order versions of Kawa): It’s just a list some of whose
carcells are keyword objects. The problem with this model is neither a human or the compiler can reliably tell when an argument is a keyword, since any variable might have been assigned a keyword. This limits performance and error checking.
A hash table (anything the implement java.util.Map)
whose keys are strings or keyword objects is
interpreted as a sequence of keyword arguments,
using the hash-table keys and values.
Constructor: argvector operand*
List of arguments represented as an immutable vector. A keyword argument takes two elements in this vector: A keyword object, followed by the value.
(define v1 (argvector 1 2 k1: 10 k2: 11 98 99)) (v1 4) ⇒ 'k2 (v1 5) ⇒ 11When
v1is viewed as a vector it is equivalent to(vector 1 2 'k1: 10 'k2: 11 98 99). (Note in this case the keywords need to be quoted, since thevectorconstructor does not take keyword arguments.) However, theargvector“knows” which arguments are actually keyword arguments, and can be examined using the(kawa arglist)library discussed below:(arglist-key-count (argvector 1 x: 2 3)) ⇒ 1 (arglist-key-count (argvector 1 'x: 2 3)) ⇒ 0 (arglist-key-count (vector 1 'x: 2 3)) ⇒ 0In this case:
(fun 'a @:v1)is equivalent to:
(fun 'a 1 2 k1: 10 k2: 11 98 99)
Constructor: arglist operand*
Similar to
argvector, but compatible withlist. If there are no keyword arguments, returns a plain list. If there is at least one keyword argument creates a specialgnu.mapping.ArgListPairobject that implements the usuallistproperties but internally wraps aargvector.
(import (kawa arglist))
In the following, args is an arglist or argvector
(or in general any object that implement gnu.mapping.ArgList).
Also, args can be a generalized list, in which case it
behaves like an argvector that has no keyword arguments.
Procedure: arglist-walk args proc
Call
proconce, in order, for each argument inargs. Theprocis called with two arguments, corresponding to(arglist-key-refandargsi)(arglist-arg-reffor eachargsi)ifrom 0 up to(arglist-arg-count(exclusive). I.e. the first argument is eitherargs)#!nullor the keyword (as a string); the second argument is the corresponding argument value.(define (print-arguments args #!optional (out (current-output-port))) (arglist-walk args (lambda (key value) (if key (format out "key: ~a value: ~w~%" key value) (format out "value: ~w~%" value)))))
Procedure: arglist-key-count args
Return the number of keyword arguments.
Procedure: arglist-key-start args
Number of prefix arguments, which is the number of arguments before the first keyword argument.
Procedure: arglist-arg-count args
Return the number of non-keyword arguments. (The count includes neither the keywords nor the corresponding values.)
Procedure: arglist-arg-ref args index
Get the
index’th argument value. Theindexcounts keyword argument values, but not the keywords themselves.(arglist-arg-ref (arglist 10 11 k1: -1 19) 2) ⇒ -1 (arglist-arg-ref (arglist 10 11 k1: -1 19) 3) ⇒ 19
Procedure: arglist-key-ref args index
The
indexcounts arguments likearglist-arg-refdoes. If this is a keyword argument, return the corresponding keyword (as a string); otherwise, return#!null(which counts are false).(arglist-key-ref (argvector 10 11 k1: -1 k2: -2 19) 3) ⇒ "k2" (arglist-key-ref (argvector 10 11 k1: -1 k2: -2 19) 4) ⇒ #!null
Procedure: arglist-key-index args key
Search for a keyword matching
key(which must be an interned string). If there is no such keyword, return -1. Otherwise return the keyword’s index as as argument toarglist-key-ref.
Procedure: arglist-key-value args key default
Search for a keyword matching
key(which must be an interned string). If there is no such keyword, return thedefault. Otherwise return the corresponding keyword argument’s value.
Procedure: apply proc argi* argrest
Argrestmust be a sequence (list, vector, or string) or a primitive Java array. (This is an extension over standard Scheme, which requires thatargsbe a list.) Calls theproc(which must be a procedure), using as arguments theargi... values plus all the elements ofargrest.Equivalent to:
(procargi*@argrest).
Syntax: constant-fold proc arg1 ...
Same as
(, unlessprocarg1...)procand all the following arguments are compile-time constants. (That is: They are either constant, or symbols that have a global binding and no lexical binding.) In that case,procis applied to the arguments at compile-time, and the result replaces theconstant-foldform. If the application raises an exception, a compile-time error is reported. For example:(constant-fold vector 'a 'b 'c)is equivalent to
(quote #(a b c)), assumingvectorhas not been re-bound.