Suppose you want to map the "add three" function over a list. You
don't need to define a name for the function, you can just use a
(lambda (n) (+ n 3)). This creates
an anonymous "add three" function.
Now suppose you want to map the "factorial" function over a list.
You start with
(lambda (x) (if (zerop x) 1 ... ,
but how can you recursively call an anonymous function? We need the
function to have a local name within its own body. One option is to
use the Y operator:
* (map 'list (Y (lambda (fact) (lambda (x) (if (zerop x) 1 (* x (funcall fact (1- x))))))) '(3 5 7)) (6 120 5040)but another popular option is to provide a new special form
* (map 'list (named-lambda fact (x) (if (zerop x) 1 (* x (fact (1- x))))) '(3 5 7)) (6 120 5040)The name
factis bound to the lambda expression only within the body of the lambda expression. You don't need to
factorialprocedure, you can just use a
A little puzzle for you: write
Just as a
let is syntactic sugar for
lambda application, a
syntactic sugar for a
named-lambda application. The
name is bound to the lambda expression that performs the variable
binding, so you can use that name to make a recursive call. In
effect, you can re-invoke the
named-let expression with
a fresh set of values.
Scheme hackers will be familiar with
named-let, but it
isn't usual in Common Lisp. It's an easy transformation:
(named-let recur ((x '(a list)) (y 22)) (body)) => (funcall (named-lambda recur (x y) (body)) '(a list) 22)
named-letis the bee's knees for ad hoc iteration. The iteration variables are bound to their initial values by the
named-let, and the body can initiate the next iteration by tail-calling the
named-letwith the updated values for the iteration variables. Since there is no constraint on where or when you iterate, or how you update the iteration variables, this allows very general iteration.
I have seen a tendency for Scheme hackers to overdo it with named
lets. You don't need a
will do. It's usually better to express an iteration through a
higher order function than to write yet another ad hoc
loop in your code. But
named-let is a useful and
powerful tool when the simpler methods aren't cutting it.
Here's what I came up with
(defmacro named-lambda (name (&rest arglist) &body body) `(labels ((,name ,arglist ,@body)) (function ,name)))