What is the difference between defining a function inline or not? - binding

I'm working through the book Structure and implementation of computer programs and in one of the chapters there were some code used to calculate the factorial of a number:
(define (factorial n)
(fact-iter 1 1 n))
(define (fact-iter product counter max-count)
(if (> counter max-count)
product
(fact-iter (* counter product)
(+ counter 1)
max-count)))
Earlier in the book I learned that I can define functions inline in another function like this:
(define (factorial n)
(define (fact-iter product counter max-count)
(if (> counter max-count)
product
(fact-iter (* counter product)
(+ counter 1)
max-count)))
(fact-iter 1 1 n))
I know that using the second approach fact-iter won't be accessible outside of the scope of factorial but I was wondering what happens actually when I run the second version of factorial?
A new local binding for the symbol fact-iter gets defined and a new function created or this binding is created only once when the program compiles?
I'm coming from a java background and this is not yet clear for me.

It rather depends on the Scheme implementation (strategies for which are discussed in subsequent chapters of SICP). Conceptually, a new function gets defined/compiled in each call to factorial per your second definition of it. However, a good compiler can transform this code so that it's much more like your first definition.
Since this construct is so common in Scheme (the idiomatic way of writing a loop being the named-let construct, which also defines functions on the fly), Scheme compilers should be pretty good at doing this optimization. And in fact your example is easy to handle for an optimizer since the inner function's definition does not actually depend on any variables bound by the outer function, so it can be lifted out almost as-is (only the name may have to be changed).

It is never the case that a new function gets compiled with each call to factorial. A function is formally a piece of code and an environment; it is the environment that can change with each call. For example:
(define (find x l)
(define (equal-to-x y) (equal? x y))
....)
In the above, every call to 'find' will produce a new function 'equal-to-x'. The 'environment' of the 'equal-to-x' function references a variable 'x' that is defined in another scope. However, a suitably good compiler may notice that equal-to-x is never returned or bound to an out-of-scope variable and thus the compiler may 'inline' the code - thereby not needing a new function (code + environment).
In your code, the free references (+, *, and >) of the internally defined fact-iter (your second case) are all globally defined and the fact-iter function is not returned (or bound). Thus a good enough compiler would inline it.
Here is a case of a not very good compiler. You can see in the disassembly of 'find' that a function/closure (code + environment) is created and in the disassembly of 'ex' that an environment reference is used (to get at 'x').
=> (define find (lambda (x l)
(define ex (lambda (y) (= x y)))
(ex (car l))))
(=>)
=> (sys:disassemble find)
;; Address : 0x00327e90
;; Label : find
;; Constants:
;; 0: #t
;; 1: #[<code> ex 1]
;; 2: (<cons> 6)
;; Code :
;; 0-1: explode 2
;; 2-3: check 2
;; 4-5: get-loc 0
;; 6-8: closure 1, 1
;; 9-10: get-loc 2
;; 11-13: get-loc-res 1, 2
;; 14: cons$car
;; 15-16: call-tail-check 1
;; :
;; Address : 0x0031fb40
;; Label : ex
;; Constants:
;; 0: #t
;; 1: (<number> 1 142 42 154 158)
;; Code :
;; 0-1: explode 1
;; 2-3: check 1
;; 4-6: get-env-res 0, 1
;; 7-9: get-loc-res 0, 1
;; 10: number$=
;; 11-12: return 1
;; :
;; Env :
#[<function> find 2]

Related

order matters with return-from in SBCL

I'm on Day 3 of trying to learn Common Lisp (SBCL) by doing Advent of Code. I understand there is more than one type of return. I'm wondering if someone could explain to me why the following function will return nil (this makes sense)
(defun fn (n)
(cond ((zerop n)
(return-from fn nil))
(t
(write-line "Hello World")
(fn (- n 1)))))
but the following function will return "Hello World" (this does not make sense to me).
(defun fn (n)
(cond ((zerop n)
(return-from fn nil))
(t
(fn (- n 1))
(write-line "Hello World"))))
I found a great post covering some aspects of SBCL's return behaviour here, but to my understanding it doesn't seem to address this particular detail.
EDIT: a loop call is a more sensible way of writing this function, but it is not the way that I discovered this behaviour. My suspicion is that this behaviour arises because fn is called recursively.
(I started writing this before Sylwester's answer, which is mostly better I think.)
A critical difference between Lisp-family languages and many other languages is that Lisp-family languages are 'expression languages'. What this means technically is that languages like (say) C or Python there are two sorts of constructs:
expressions, which have values;
statements, which do not;
While in Lisp-family languages there is one sort of thing: expressions, which have values. Lisp-family languages are sometimes called 'expression languages' as a result of this.
This makes a huge difference if you want to write functions, which are things which return values (a function call is an expression in other words).
Conventional languages (Python as an example)
In a language which is not an expression language then if you're defining a function and find yourself in the middle of some construct which is a statement and you want to return a value, you have to use some special magic construct, often called return to do that. So in Python, where conditionals are statements, you might write:
def fib(n):
if n < 2:
return n
else:
return fib(n - 1) + fib(n - 2)
And in fact you have to use return because the body of a function definition in Python is a series of statements, so to return any kind of value at all you need to use return.
In fact, Python (and C, and Java &c &c) have a special form of a conditional which is an expression: in Python this looks like this:
def fib(n):
return n if n < 2 else (fib(n - 1) + fib(n - 2)
It looks different in C but it does the same thing.
But you still need this annoying return (OK, only one of them now) & that brings to light another feature of such languages: if some place in the syntax wants a statement you generally need to have a statement there, or if you can put an expression there its value just gets dropped. So you can try something like this:
def fib(n):
n if n < 2 else (fib(n - 1) + fib(n - 2)
And that's syntactically OK -- the expression gets turned into a statement -- but it fails at runtime because the function no longer returns a useful value. In Python you can get around this if you want people to hate you:
fib = lambda n: n if n < 2 else fib(n - 1) + fib(n - 2)
Python people will hate you if you do this, and it's also not useful, because Python's lambda only takes expressions so what you can write is crippled.
Lisp
Lisp has none of this: in Lisp everything is an expression and therefore everything has a value, you just need to know where it comes from. There is still return (in CL, anyway) but you need to use it much less often.
But, of course people often do want to write programs which look like 'do this, then do this, then do this', where most of the doing is being done for side-effect, so Lisps generally have some kind of sequencing construct, which lets you just have a bunch of expressions one after the other, all but (typically) one of which get evaluated for side-effect. In CL the most common sequencing construct is called progn (for historical reasons). (progn ...) is an expression made of other expressions, and its value is the value of last expression in its body.
progn is so useful in fact that a bunch of other constructs have 'implicit progns' in them. Two examples are function definitions (the body of defun is an implicit progn) and cond (the body of a cond-clause is an implicit `progn).
Your function
Here is your function (first version) with its various parts notated
(defun fn (n)
;; the body of fn is an implicit progn with one expression, so
;; do this and return its value
(cond
;; the value of cond is the value of the selected clause, or nil
((zerop n)
;; the body of this cond clause is an implicit progn with on
;; expression so do this and ... it never returns
(return-from fn nil))
(t
;; the body of this cond clause is an implicit progn with two expressions, so
;; do this for side-effect
(write-line "Hello World")
;; then do this and return its value
(fn (- n 1)))))
Here is the second version
(defun fn (n)
;; the body of fn is an implicit progn with one expression, so
;; do this and return its value
(cond
;; the value of cond is the value of the selected clause, or nil
((zerop n)
;; the body of this cond clause is an implicit progn with on
;; expression so do this and ... it never returns
(return-from fn nil))
(t
;; the body of this cond clause is an implicit progn with two expressions, so
;; do this for side-effect
(fn (- n 1))
;; then do this and return its value
(write-line "Hello World"))))
So you can see what is happening here: in the first version the value that gets returned is either nil or the value of the recursive call (also nil). In the second version the value that gets returned is either nil or whatever write-line returns. And it turns out that write-line returns the value of its argument, so that's what you get if you call it with an integer greater than zero.
Why have return-from at all in Lisp?
One thing that should be immediately clear from this whole expression-language thing is that you hardly ever need to explicitly return something in Lisp: you just have an expression that computes the value you want. But there are two good uses (which perhaps are really the same use) of explicit returns.
The first is that sometimes you are doing some big search for something in the form of a bunch of nested loops and at some point you just want to say 'OK, found it, here's the answer'. You can do that in one of two ways: you can carefully structure your loops so that once you find what you're after they all terminate nicely and the value gets passed back up, or you can just say 'here's the answer'. The latter thing is what return-from does: it just says 'I'm done now, unwind the stack carefully and return this':
(defun big-complicated-search (l m n)
(dotimes (i l)
(dotimes (j m)
(dotimes (k n)
(let ((it (something-involving i j k l m n)))
(when (interesting-p it)
(return-from big-complicated-search it)))))))
And return-from does this in the right way:
(defun big-complicated-file-search (file1 file2)
(with-open-file (f1 file1)
(with-open-file (f2 file2)
...
(when ...
(return-from big-complicated-search found)))))
When you call this, and when the thing is found, return-from will make sure that the two files you have opened are properly closed.
The second, which is really almost the same thing, is that sometimes you need to just give up, and return-from is a good way of doing this: it returns immediately, deals with clean-ups (see above) and is generally a nice way of saying 'OK, I give up now'. At first blush this seems like something you would do with some kind of exception-handling system, but in fact there are two critical differences:
in an exception-handling system (which CL has, of course), you need some kind of exception to raise so you might need to invent something;
exception-handling systems are dynamic not lexical: if you raise an exception then the thing that gets to handle it is hunted for up the stack dynamically: this means that you're at the mercy of anyone who stuck a handler in the way and it also typically rather slow.
Finally the exceptional-return-via-error-handling-mechanism is just, well, horrid.
Your code:
(defun fn (n)
(cond ((zerop n) (return-from fn nil))
(t (write-line "Hello World") (fn (- n 1)))
)
)
There is a bunch of things slightly wrong with above code:
(defun fn (n)
(cond ((zerop n) (return-from fn nil)) ; 1) the return from is not needed
(t (write-line "Hello World") (fn (- n 1))) ; 2) this line is not correctly
; indented
) ; 3) dangling parentheses Don't. Never.
; also: incorrect indentation
)
the first cond clause already returns a value, just write nil as the return value. Then the whole cond returns this value. It is very rare that you need return or return-from from a cond clause.
use an editor to indent your code. In GNU Emacs / SLIME the command control-meta-q will indent the expression. For help about the editor commands in the current mode see: control-h m for mode help.
indent correctly and don't use dangling parentheses. They are useless in Lisp. Learn to use the editor to correctly indent code - that's much more useful than to place wrongly indented parentheses on their own line. tab indents the current line.
It's more useful to format the code like this for a beginner:
(defun fn (n)
(cond ((zerop n)
(return-from fn nil))
(t
(write-line "Hello World")
(fn (- n 1)))))
Code then will look more like a prefix tree.
Also don't forget to disable inserting tabs in GNU Emacs Put this into your emacs init file: (setq-default indent-tabs-mode nil). You can evaluate Emacs Lisp expressions also on the fly with meta>-:.
Now according to 1. above code is usually written as:
(defun fn (n)
(cond ((zerop n)
nil)
(t
(write-line "Hello World")
(fn (- n 1)))))
When n is zero, the first clause is selected and its last value is returned. The other clauses are not looked at -> cond returns nil -> the function fn returns nil.
Usually I would write above recursive function like this:
(defun fn (n)
(unless (zerop n)
(write-line "Hello World")
(fn (- n 1))))
unless returns nil if (zerop n) is true. Another variant:
(defun fn (n)
(when (plusp n)
(write-line "Hello World")
(fn (- n 1))))
You CAN use return-from, but in case it was not clear: you don't need it most of the time.
Unlike C language family Lisp has the feature that everything is expressions. That means you "return" the result of an expression. eg.
(+ (if (< x 0)
(- x)
x)
3)
Here the result of the if is that it will be the absolute value of x. Thus if x is -5 or 5 the result of the expression is 8. You can write abs like this:
(defun my-abs (v)
(if (< v 0)
(- v)
v))
Notice I do not use return. THe result of the if is the last expression and that means the result of that is the result of my-abs.
Your two functions can be written like this:
(defun fn1 (n)
(cond
((zerop n) nil)
(t (write-line "Hello World") (fn1 (- n 1)))))
And
(defun fn2 (n)
(cond
((zerop n) nil)
(t (fn2 (- n 1)) (write-line "Hello World"))))
Needless to say (write-line "Hello World") returns its argument in addition to print the argument. Thus whenever it is the last expression it will be the result.
For every n above 0 it will do the recursions first and each end every one except the first will return "Hello World". If you call (fn2 0) the result is nil, the same as fn1.
EDIT
One might ask what is the purpose of return and return-from when there obviously is little use for it. If you want something else than the default result in a loop macro the common way to do it by finally clause.
(defun split-by (test list &key (return-form #'values))
"Split a list in two groups based on test"
(loop :for e :in list
:if (funcall test e)
:collect e :into alist
:else
:collect e :into blist
:finally (return (funcall return-form alist blist))))
(split-by #'oddp '(1 2 3 4) :return-form #'list)
; ==> ((1 3) (2 4))
Another way is if you are doing recursion and want to cancel everything when you know the result you can use return-from:
(defun find-tree-p (needle haystack &key (test #'eql))
"search the tree for element using :test as comparison"
(labels ((helper (tree)
(cond ((funcall test tree needle)
(return-from find-tree t))
((consp tree)
(helper (car tree))
(helper (cdr tree)))
(t nil))))
(helper haystack)))
(find-tree '(f g) '(a b c (d e (f g) q) 1 2 3) :test #'equal)
; ==> (f g) ; t
Now if you hadn't done return-from you would have had logic to check the returned value to see if you needed to continue or not. If you want to process elements and don't want to pass twice to check validity before computing the result, you can just start computing and use return-from as a call/cc. This function can be used to map over lists of lists and it stops at the shortest list so needs to become () when the first sublist is empty:
(defun cdrs (lists)
"return the cdrs if all elements are cons, () otherwise"
(loop :for list :in lists
:when (null list) :do (return-from cdrs '())
:collect (cdr list)))
(cdrs '((a) (b) (c))) ; ==> (nil nil nil)
(cdrs '((a) (b) ())) ; ==> ()

Reassigning a global variable within a function without passing variable name

As described in the title I try to solve the following problem:
(setq s ())
(defun reassign (val)
(setq val 10))
(reassign s)
(print s)
-> Output: s = nil
I want reassign to destructively assign s = 10.
Is there an easy way to handle this, without using the variable name s within the function & only changing the function? (may Macros be included?) I would be grateful for any advice! :)
(defun reassign (val)
(setq val 10))
(reassign s)
When you call (reassign s), the value of s is passed down to reassign, where it is locally bound to val. That would be nil in your case, assuming you already declared s with DEFVAR before setting it to () (see setq and defvar in Lisp).
Inside reassign, the call to SETQ changes the local binding.
Global binding
Each symbol can hold a global value.
If you want to change the value cell of a symbol, use the SYMBOL-VALUE accessor:
(setf (symbol-value 's) 10)
Notice how s is quoted. You are not changing the symbol currently bound to s (which would be nil, a constant variable), but the s symbol itself. (SETF SYMBOL) is like calling SET directly.
Lexical and dynamic binding
If however, you want to modify any kind of place, and in particular lexical and dynamic variable bindings, you need to define a macro:
(defmacro reassign (place)
`(setf ,place 10))
SETF expands into the code necessary to update a place. You could also give (gethash key table) instead of just an unquoted variable, which would then update the content of a table.
In the case of local variables, the code that calls reassign will eventually expands into a call to the special operator SETQ, which knows how to change lexical bindings (it also handles SYMBOL-MACROLET bindings).
Yes, you guessed correctly. you need a macro.
(defmacro reassign (var &optional (val 10)) `(setq ,var ,val))
(defvar s ()) ;; #Svante remarked that setq can be dangerous to create a variable
s ;; NIL
(reassign s)
s ;; 10
;; the `&optional (val 10)` makes the value optional and 10 to the
;; default value of val if not given.
In your example
(defun reassign (val) (setq val 10))
val is the first argument of the special form of setq: the val in the setq doesn't become s although you gave it reassign for val. It stays val so that you assign 10 in the functional scope to val. You can make this visible by:
(setq s ())
(defun reassign (val)
(print "You gave for `val`:")
(print val)
(setq val 10)
(print "The form assigned 10 literally to val")
(print "Proof: Print out val in this scope:")
(print val))
(reassign s)
;;
;; "You gave for `val`:"
;; NIL
;; "The form assigned 10 literally to val"
;; "Proof: Print out val in this scope:"
;; 10
;; 10
(print val)
*** - SYSTEM::READ-EVAL-PRINT: variable VAL has no value
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead of VAL.
STORE-VALUE :R2 Input a new value for VAL.
ABORT :R3 Abort main loop
;; since val has not been initiated before
In addition, the setq of the function is executed within the functional scope. That is why outside the function val keeps the old value.
(defvar val ()) ;; NIL
(print val) ;; NIL
(defun reassign (val)
(print "You gave for `val`:")
(print val)
(setq val 10)
(print "The form assigned 10 literally to val")
(print "Proof: Print out val in this scope:")
(print val))
(reassign 'whatever) ;; inside function val becomes 10
;;
;;"You gave for `val`:"
;;WHATEVER
;;"The form assigned 10 literally to val"
;;"Proof: Print out val in this scope:"
;;10 ;; val becomes indeed 10 until leaving function
;;10
;; but retains old value after leaving the function
(print val)
;;
;; NIL
;; NIL
The macro in contrast replaces the macro call (reassign s) by the form (setq s 10). So when executed, the reassignment takes place within the environment where we defined (defvar s ()).
Therefore after the reassignment, s keeps the newly assigned value, since it was reassigned in the working environment.

Scheme and Shallow Binding

(define make (lambda (x) (lambda (y) (cons x (list y)))))
(let ((x 7)
(p (make 4)))
(cons x (p 0)))
I'm new to Scheme and functional program, so I am a bit clunky with walking through programs, but I get that if I used deep binding this program will return (7 4 0). Makes sense. What would this program do using shallow binding? I get this may sound dumb but is the p in the line with cons a redefinition? So in that case, we would return (7 0)?
Basically, I understand the concept of deep v. shallow binding, but I feel like I'm jumbling it up when looking at Scheme because I'm not crazy familiar with it.
Deep or shallow binding is an implementational technique and can not be observed from inside the program. The difference for the programmer is between lexical and dynamic scoping rules, but both can be implemented with any of the two techniques (i.e. one notion has got nothing to do with the other).
Deep or shallow refers to the choice of stack frame to hold a given outer scoped variable's binding. In deep binding there is a chain of frames to be accessed until the correct frame is entered holding the record for the variable; in shallow binding all bindings are present in one, shallow environment. See also "rerooting" (which only makes sense in the context of shallow binding implementation of lexical scoping).
To your specific question, under lexical scoping rules your code would return (7 4 0) and under dynamic - (7 7 0), because the call ((lambda(y) (list x y)) 0) is done inside the dynamic scope of x=7 binding (as a side note, (cons x (list y)) is the same as (list x y)):
x = 7
p = (lambda (y) (list x y)) ; x=4 is unused, in p=(make 4)
(cons 7 (p 0)) == (list 7 7 0) ; 'x' in this line and in lambda body for p
; both refer to same binding that is
; in effect, i.e. x=7
NB same terms (deep/shallow binding) are used in other language(s) now with completely different meaning (they do have something to do with the scoping rules there), which I don't care to fully understand. This answer is given in the context of Scheme.
Reference: Shallow Binding in LISP 1.5 by Baker, Henry G. Jr., 1977.
See this wikipedia article for a discussion on scoping (it mentions lexical/dynamic scoping and deep/shallow binding) bearing in mind that Scheme is lexically scoped. Will Ness' answer provides additional information.
For now, let's see step-by-step what's happening in this snippet of code:
; a variable called x is defined and assigned the value 7
(let ((x 7)
; make is called and returns a procedure p, inside its x variable has value 4
(p (make 4)))
; 7 is appended at the head of the result of calling p with y = 0
(cons x (p 0)))
=> '(7 4 0)
Notice that in the second line a closure is created in the lambda returned by make, and the variable x inside will be assigned the value 4. This x has nothing to do with the outer x, because Scheme is lexically scoped.
The last line is not a redefinition, as mentioned in the previous paragraph the x inside make is different from the x defined in the let expression.

Ordered set notation

I'm given the following implementation of an ordered structure at my disposal:
;; os-empty an empty set
;; (os-singleton e) produces a set with one element e
;; (os-member s e) produces true if e is a member of s; false otherwise
;; (os-union s t) produces union of s and t in time
;; O(min(|s|,|t|) log max(|s|,|t|)
;; (os-intersection s t) produces intersection of s and t in time
;; O(min(|s|,|t|) log max(|s|,|t|)
;; (os-difference s t) produces difference s \ t in time
;; O(min(|s|,|t|) log max(|s|,|t|)
;; (os-min s) produces the to-min element of s, or to-min-ident
;; running time: O(log |s|)
;; (os-max s) produces the to-max element of s, or to-max-ident
;; running time: O(log |s|)
;; (os-after s e) produces the to-min element of s which is to> than e
;; running time: O(log |s|)
;; (os-before s e) produces the to-max element of s which is to< than e
;; running time: O(log |s|)
;; (os-op) produces the result of applying to-op over all e in s
;; running time: O(1)
The code can be found in the following files: https://www.student.cs.uwaterloo.ca/~cs136/assignments/a8/ordered-set.rkt and https://www.student.cs.uwaterloo.ca/~cs136/assignments/a8/total-order.rkt
The structure doesn't allow duplicates in it. Here is my problem: I need to write a program that writes each distinct integer in ascending order, followed by a space, followed by the number of times it occurs in the input, to a separate line of output.
Sample Input
1
3
2
1
Output for Sample Input
1 2
2 1
3 1
Here is what I've got:
;;Prints in ascending order
(define (printer e s)
(cond
[(equal? (to-unhide e) +inf.0) (printf "")]
[else (printf "~a\n" (to-unhide e)) (printer (os-after s e) s)]))
(define (main)
(define x (read))
(cond
[(eof-object? x) (printer (os-min o) o)]
[(os-member o (os-singlton (to-hide x))) ....... <--- What to do?
[else (set! o (os-union (os-singleton (to-hide x)) o)) (main)]))
(main)
My problem is how to make a counter based on the x, and how to make that counter special for x... i was thinking about making a function that produces variables but I don't think that is possible for Scheme. Any suggestions how to remember the amount of times an input has been used using this structure ?
Separate your task into smaller chunks.
Here is one way to divide your tasks into smaller functions.
Write list->ordered-set : list-of-numbers -> ordered-set
That converts a list of numbers in to an ordered set.
Write read-numbers : list-of-strings -> list-of-numbers
That converts a lists of strings into a list of numbers
Write read-all-lines : -> list-of-strings
That that repeatedly uses read-line until eof is seen,
and returns a list of all lines read.
Use a printer on (list->ordered-set (read-numbers (read-all-lines))).

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.
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)))
destructuring-bind combines destructors with binding. A destructor is a function that lets you access a part of a data structure. car and cdr are simple destructors to extract the head and tail of a list. getf is a general destructor framework. Binding is most commonly performed by let. In this example, fns is (#'list #'round #'sqrt) (the arguments to compose), so (reverse fns) is (#'sqrt #'round #'list). Then
(destructuring-bind (fn1 . rest) '(#'sqrt #'round #'list)
...)
is equivalent to
(let ((tmp '(#'sqrt #'round #'list)))
(let ((fn1 (car tmp))
(rest (cdr tmp)))
...))
except that it doesn't bind tmp, of course. The idea of destructuring-bind is that it's a pattern matching construct: its first argument is a pattern that the data must match, and symbols in the pattern are bound to the corresponding pieces of the data.
So now fn1 is #'sqrt and rest is (#'round #'list). The compose function returns a function: (lambda (&rest args) ...). Now consider what happens when you apply that function to some argument such as 4. The lambda can be applied, yielding
(reduce #'(lambda (v f) (funcall f v))
'(#'round #'list)
:initial-value (apply #'sqrt 4)))
The apply function applies fn1 to the argument; since this argument is not a list, this is just (#'sqrt 4) which is 2. In other words, we have
(reduce #'(lambda (v f) (funcall f v))
'(#'round #'list)
:initial-value 2)
Now the reduce function does its job, which is to apply #'(lambda (v f) (funcall f v)) successively to the #'round and to #'list, starting with 2. This is equivalent to
(funcall #'list (funcall #'round 2))
→ (#'list (#'round 2))
→ '(2)
Okay, here goes:
It takes the functions given, reverses it (in your example, it becomes (#'sqrt #'round #'list)), then sticks the first item into fn1, and the rest into rest. We have: fn1 = #'sqrt, and rest = (#'round #'list).
Then it performs a fold, using (apply sqrt args) (where args are the values given to the resulting lambda) as the initial value, and with each iteration grabbing the next function from rest to call.
For the first iteration you end up with (round (apply sqrt args)), and the second iteration you end up with (list (round (apply sqrt args))).
Interestingly, only the initial function (sqrt in your case) is allowed to take multiple arguments. The rest of the functions are called with single arguments only, even if any particular function in the chain does a multiple-value return.
This example stumped me for a day. I could finally understand it by renaming some of the arguments and commenting each line before it made sense. Below is what helped me explain it to myself.
In the book example using the call:
(mapcar (compose #'list #'round #'sqrt) '(4 9 16 25))
The parameter functions becomes (#'LIST #'ROUND #'SQRT)
(defun compose (&rest functions)
(destructuring-bind (fx . fxs) (reverse functions)
;; fx becomes #'SQRT
;; fxs becomes '(#'ROUND #'LIST)
#'(lambda (&rest args) ; This is the function returned as result.
;; The args parameter will be (4) on the mapcar's first
;; iteration on the (4 9 16 25) list passed in the call:
;; (mapcar #'(compose #'List #'round #'sqrt) '(4 9 16 25)) => ((2) (3) (4) (5))
;; or e.g. the (4) in (funcall (compose #'list #'sqrt '(4)) => (2.0)
;; Note that args is not ((#'ROUND #'LIST)).
(reduce #'(lambda (x y) (funcall y x))
;; fxs is (#'ROUND #'LIST) - captuted as closure since it is now
;; locally unbound.
fxs
;; Initial value is: (apply #'SQRT '(4) => 2.0.
;; In Paul Graham's example, the mapcar passes
;; each square number individually.
;; The reverse order of parameters in the second lambda
;; first invokes: (ROUND 2.0) => 2
;; and then invokes: (LIST 2) => (2)
:initial-value (apply fx args)))))

Resources