Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compose example in Paul Graham's ANSI Common Lisp

Can anybody explain an example in Paul Graham's ANSI Common Lisp page 110?

The example try to explain the use &rest and lambda to create functional programming facilities. One of them is a function to compose functional arguments. I cannot find anything explaining how it worked. The code is as follows:

(defun compose (&rest fns)
  (destructuring-bind (fn1 . rest) (reverse fns)
    #'(lambda (&rest args)
        (reduce #'(lambda (v f) (funcall f v))
                rest
                :initial-value (apply fn1 args)))))

The usage is:

(mapcar (compose #'list #'round #'sqrt)
        '(4 9 16 25))

The output is:

((2) (3) (4) (5))

Line 2 and 6 look especially like magic to me.

like image 647
sunwc Avatar asked May 08 '11 14:05

sunwc


1 Answers

The compose function returns a closure that calls each of the functions from last to first, passing on the result of each function call to the next.

The closure resulting from calling (compose #'list #'round #'sqrt) first calculates the square root of its argument, rounds the result to the nearest integer, then creates a list of the result. Calling the closure with say 3 as argument is equivalent to evaluating (list (round (sqrt 3))).

The destructuring-bind evaluates the (reverse fns) expression to get the arguments of compose in reverse order, and binds its first item of the resulting list to the fn1 local variable and the rest of the resulting list to the rest local variable. Hence fn1 holds the last item of fns, #'sqrt.

The reduce calls each the fns functions with the accumulated result. The :initial-value (apply fn1 args) provides the initial value to the reduce function and supports calling the closure with multiple arguments. Without the requirement of multiple arguments, compose can be simplified to:

(defun compose (&rest fns)
  #'(lambda (arg)
      (reduce #'(lambda (v f) (funcall f v))
              (reverse fns)
              :initial-value arg)))
like image 168
Terje Norderhaug Avatar answered Oct 03 '22 21:10

Terje Norderhaug