Multiple arity

Chapter: Multiple arity

We return to the question of how to deal with composing procedures in which we don't know ahead of time the number of arguments. In other words, can we compose functions of varying arities? For example, suppose a is a procedure of four arguments and b is a procedure of three arguments.

Q. 9
What will be some problems if we try to do (compose a b) using compose as defined in the first Chapter Composing and Currying?


Scheme has a number of facilities to help us deal with multiple arity. A set of arguments can be combined into a single list and the Scheme primitive apply allows us to execute a procedure with a list as the arguments for the procedure call.

For example, mag-4 computes the magnitude of a four element list. The notion of magnitude comes from vectors in mathematics (not to be confused with Scheme vectors!) in which the magnitude of a vector is is the square-root of the sums of the squares of its components.

(define mag-4
  (lambda (a1 a2 a3 a4)
    (sqrt (+ (* a1 a1) (* a2 a2) (* a3 a3) (* a4 a4)))))

(define mag-4l
  (lambda (ls)
    (apply mag-4 ls)))

> (mag-4l '(10.5 10.1 3.5 2.0))
15.116547224812946
> (mag-4l 10.5 10.1 3.5 2.0)
procedure mag-4l: expects 1 argument, given 4: 10.5 10.1 3.5 2.0
> (mag-4 10.5 10.1 3.5 2.0)
15.116547224812946

This simple use of apply allows us to transform mag-4, a procedure of four arguments, into mag-4l which takes one argument, a list of four elements. Similarly, we can return multiple arguments by returning a list. This leads us to a more general multi-variable version of compose.

(define compose
  (lambda (f g)
    (lambda (ls)
      (apply f (apply g ls)))))

Q. 10
This works well except for one annoyance. Try some examples. What is the problem?


We can use a Scheme feature called unrestricted lambda or variable-arity lambda to deal with this. Procedures defined using unrestricted-lambda have the following form:

(define proc
  (lambda lst
    ... body ...))

Note the intentional lack of parentheses around lst. When applied to any number of arguments, proc will have access to all the actual arguments as a single list which it refers to as "lst". The individual arguments in the list lst can be accessed using the usual list operations car, cadr, cdr, and so on.

For example, here is a silly function that asks to be fed if given no arguments, tells you if it is a number in the case that it's given just one argument, and applies the first argument to the rest in case it's fed many arguments. :

(define silly
  (lambda args
    (cond
      ((null? args) 'feed-me)
      ((null? (cdr args)) (number? (car args)))
      (else (apply (car args) (cdr args))))))

> (silly 24)
#t
> (silly +)
#f
> (silly + 1 2 3 4 5)
15
> (silly)
feed-me
>

As you have probably noticed by now, Scheme's +,*, and - procedures are designed using unrestricted lambda so that:

> (+ 10 12 9 3)
34
> (- 6 -3 2 8)
-1
>

Here is compose once again. This version deals properly with procedures of more than one argument:

(define compose
  (lambda (f g)
    (lambda ls
      (apply f (apply g ls)))))

There is still an unpleasantness and that is that since we are using "apply" with f we must not allow g to return an atomic value -- it must return a list.

Q. 11
What happens if you type
((compose add1 +) 2 3)



Exercise 8




rhyspj@gwu.edu