let and flet in emacs lisp

笑着哭i 提交于 2019-12-20 08:29:25

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!