A procedure's arity is the number of arguments it takes.
You'll probably have noticed that while some of Scheme's built-in procedures
always take the same number of arguments (for instance, the arity of the
cons procedure is 2, and the arity of the predicate
char-uppercase? is 1), others have variable arity --
that is, they can take any number of arguments. All one can say about the
arity of a Scheme procedure such as list, +, or
string-append is that it is some non-negative integer.
Still other Scheme procedures, such as map and
display, require a certain fixed minimum number of arguments,
but will accept one or more additional arguments if they are provided.
The arity of map is ``2 or more''; the arity of
display is ``1 or 2.'' These procedures, too, are said to
have variable arity, because their arity varies from one call to another.
It is possible for the programmer to define new variable-arity procedures
in Scheme, by using alternate forms of the lambda-expression.
In all of the programmer-defined procedures that we have seen so far, the
keyword lambda has been followed by a list of parameters --
names for the values that will be supplied by the caller when the procedure
is invoked. If, instead, what follows lambda is a single
identifier -- not a list, but a simple identifier, not enclosed in
parentheses -- then the procedure denoted by the
lambda-expression will accept any number of arguments, and the
identifier following lambda will name a list of all the
arguments supplied in the call.
Here's a simple example: We'll define a display-line
procedure that takes any number of arguments and prints out each one (by
applying the display procedure to it), then terminates the
output line (by invoking newline). Note that in the
lambda-expression, the identifier arguments
denotes a list of all the items to be printed:
(define display-line
(lambda arguments
(let loop ((rest arguments))
(if (null? rest)
(newline)
(begin
(display (car rest))
(loop (cdr rest)))))))
When display-line is invoked, however, the caller does not
assemble the items to be printed into a list, but just supplies them as
arguments:
> (display-line "+--" "Here is a string!" "--+") +--Here is a string!--+ > (display-line "ratio = " 35/15) ratio = 7/3
Try out some other calls to display-line to check what it prints. For example, try the following:
(display-line "going" "going" "gone") (display-line "countdown:" 5 4 3 2 1 "done") (display-line) ;; apply display-line to no arguments
Explain your results.
The current version of display-line prints all text together without spaces. Modify the code, so that one space is printed between each value specified for display-line. Thus, the first sample run above should print
+-- Here is a string! --+
Write a procedure named call-arity that takes any number of
arguments and returns the number of arguments it received (ignoring their
values):
> (call-arity 'a #\b "c" '(d)) 4 > (call-arity 0.0) 1 > (call-arity) 0
If the programmer wishes to require some fixed minimum number of arguments
while permitting (but not requiring) additional ones, she can use yet
another form of the lambda-expression, in which a dot is
placed between the last two identifiers in the parameter list. All the
identifiers to the left of this dot correspond to single required
arguments. The identifier to the right of the dot designates the list of
all of the remaining arguments, the ones that are optional.
For instance, we can define a procedure called
display-separated-line that always takes at least one
argument, separator, but may take any number of additional
arguments. Display-separated-line will print out each of the
additional arguments (by invoking display) and terminate the
line, just as display-line does, but with the difference that
a copy of separator will be displayed between any two of the
remaining values. Here is some sample output:
> (display-separated-line "..." "going" "going" "gone") going...going...gone > (display-separated-line ":-" 5 4 3 2 1 'done) 5:-4:-3:-2:-1:-done > (display-separated-line #\space "+--" "Here is a string!" "--+") +-- Here is a string! --+ > (display-separated-line #\tab 1997 'foo 'wombat 'quux) 1997 foo wombat quux
And here is the definition of the procedure:
(define display-separated-line
(lambda (separator . arguments)
(if (null? arguments)
(newline)
(let loop ((rest arguments))
(display (car rest))
(if (null? (cdr rest))
(newline)
(begin
(display separator)
(loop (cdr rest))))))))
What happens if you invoke display-separated-line without
giving it any arguments? What happens when only one argument is given?
Revise the display-separated-line procedure so that it
displays the separator at the beginning and end of each line, as well as
between successive arguments.
The dot notation can be used to specify any number of initial values. Thus, a parameter list of the form
(first-value second-value . remaining-values)
indicates that the first two arguments are required, while additional
arguments will be collected into a list named
remaining-values.
Modify the definition of the display-separated-lines procedure
so that it takes an output port as its first (required) argument, the
separator as its second (required) argument, and any number of values to
be printed as additional (optional) arguments. The procedure should write
the line, with separators, to the specified output port rather than to the
interaction window.
Write a procedure that takes one or more numbers and computes their
arithmetic mean (in other words, their average). For instance,
(average 3 5 7 11 14) should return 8. (Note that it would
not make sense to invoke this procedure with zero arguments.)
This document is available on the World Wide Web as
http://www.math.grin.edu/courses/Scheme/spring-1998/variable-arity.html
created March 22, 1997
last revised June 21, 1998
Henry Walker (walker@math.grin.edu) and John David Stone (stone@math.grin.edu)