问题
I don't know if you would call it the canonical formulation, but to bind a local function I am advised by the GNU manual to use 'flet':
(defun adder-with-flet (x)
(flet ( (f (x) (+ x 3)) )
(f x))
)
However, by accident I tried (after having played in Scheme for a bit) the following expression, where I bind a lambda expression to a variable using 'let', and it also works if I pass the function to mapcar*:
(defun adder-with-let (x)
(let ( (f (lambda (x) (+ x 3))) )
(car (mapcar* f (list x)) ))
)
And both functions work:
(adder-with-flet 3) ==> 6
(adder-with-let 3) ==> 6
Why does the second one work? I cannot find any documentation where 'let' can be used to bind functions to symbols.
回答1:
Unlike Scheme, Emacs Lisp is a 2-lisp, which means that each symbol has two separate bindings: the value binding and the function binding. In a function call (a b c d)
, the first symbol (a
) is looked up using a function binding, the rest (b c d
) are looked up using the value binding. Special form let
creates a new (local) value binding, flet
creates a new function binding.
Note that whether value or function binding is used for lookup depends on the position in the (a b c d)
function call, not on the type of the looked-up value. In particular, a value binding can resolve to function.
In your first example, you function-bind f
(via flet
), and then do a function lookup:
(f ...)
In your second example, you value-bind f
to a function (via let
), and then use a value lookup:
(... f ...)
Both work because you use the same kind of binding and lookup in each case.
http://en.wikipedia.org/wiki/Common_Lisp#Comparison_with_other_Lisps
回答2:
I did a quick search of the Emacs lisp manual and couldn't find any reference to 'flet
, which isn't terribly surprising since that is a part of cl
- the common-lisp package.
let will do a local binding as well, but it won't bind to the "function cell" for that symbol.
i.e. This works:
(let ((myf (lambda (x) (list x x))))
(eval (list myf 3)))
but
(let ((myf (lambda (x) (list x x))))
(myf 3))
fails with the error: "Lisp error: (void-function myf)"
flet
on the other hand, does do the binding to the function cell, so this works:
(flet ((myf (x) (list x x)))
(myf 3))
Notice the difference being that flet
allows you to use the symbol myf
directly, whereas the let
does not - you have to use some indirection to get the function out of the "value cell" and apply that appropriately.
In your example, the 'mapcar
' did the equivalent to my use of 'eval
.
回答3:
@d11wq there is `funcall' for this purpose. The following works:
(defun adder-with-let (x)
(let ((f #'(lambda (x) (+ x 3))))
(funcall f 3)))
(adder-with-let 3) ;=> 6
回答4:
You don't have to use flet
if you do not want to. You place a function in the function cell of a local symbol defined using let
as in the following example:
(let ((ALocalSymbol))
(fset 'ALocalSymbol (lambda (x) (* 2 x)))
(ALocalSymbol 4)
)
Evaluating this will return 8. Do notice the quote in front of ALocalSymbol
in (let ((ALocalSymbol))...)
. While setq
quotes symbols, fset
does not.
flet
is a syntactic sugar of sorts. Using a plain-old let
to define nil-valued symbols, allows you to choose which "cell" of a symbol to set. You could use setq
to set the symbol's value cell or fset
to set the function cell.
Hope this helps,
Pablo
来源:https://stackoverflow.com/questions/1197184/let-and-flet-in-emacs-lisp