let和flet在emacs lisp中

时间:2009-07-28 22:54:12

标签: binding elisp

我不知道你是否会把它称为规范公式,但是绑定一个本地函数我被GNU手册建议使用'flet':

(defun adder-with-flet (x)
  (flet ( (f (x) (+ x 3)) )
    (f x))
)

然而,偶然地,我尝试了(稍微使用了Scheme之后)以下表达式,其中我使用'let'将lambda表达式绑定到变量,如果我将函数传递给mapcar *它也可以工作:

(defun adder-with-let (x)
  (let ( (f (lambda (x) (+ x 3))) )
    (car (mapcar* f (list x)) ))
)

这两个功能都有效:

(adder-with-flet 3)   ==> 6
(adder-with-let 3) ==> 6

为什么第二个有效?我找不到任何文档,其中'let'可用于将函数绑定到符号。

4 个答案:

答案 0 :(得分:40)

与Scheme不同,Emacs Lisp是 2-lisp ,这意味着每个符号都有两个独立的绑定:值绑定和函数绑定。在函数调用(a b c d)中,使用函数绑定查找第一个符号(a),使用值绑定查找其余符号(b c d)。特殊格式let创建一个新的(本地)值绑定,flet创建一个新的函数绑定。

请注意,值或函数绑定是否用于查找取决于(a b c d)函数调用中的位置,而不取决于所查看的类型提升价值。特别是,值绑定可以解析为起作用。

在第一个示例中,您将函数绑定f(通过flet),然后执行函数查找:

(f ...)

在第二个示例中,您将f值绑定到函数(通过let),然后使用值查找:

(... f ...)

两者都有效,因为在每种情况下都使用相同类型的绑定和查找。

http://en.wikipedia.org/wiki/Common_Lisp#Comparison_with_other_Lisps

答案 1 :(得分:19)

我快速搜索了Emacs lisp手册,找不到对'flet的任何引用,这不是特别令人惊讶,因为它是cl的一部分 - {{3} }。

common-lisp package也会执行本地绑定,但它不会绑定到该符号的let

即。这有效:

(let ((myf (lambda (x) (list x x))))
  (eval (list myf 3)))

(let ((myf (lambda (x) (list x x))))
  (myf 3))

失败并显示错误:“Lisp error:(void-function myf)”

另一方面,

flet确实绑定到功能单元,所以这有效:

(flet ((myf (x) (list x x)))
  (myf 3))

注意区别在于flet允许您直接使用符号myf,而let则不允许 - 您必须使用一些间接来从“价值细胞“并适当地应用。

在您的示例中,“mapcar”与我对'eval的使用相同。

答案 2 :(得分:7)

@ d11wq为此目的有`funcall'。以下作品:

(defun adder-with-let (x)
  (let ((f #'(lambda (x) (+ x 3))))
    (funcall f 3)))

(adder-with-let 3) ;=> 6

答案 3 :(得分:0)

如果您不想,则不必使用flet。将函数放在使用let定义的本地符号的函数单元格中,如下例所示:

(let ((ALocalSymbol))
  (fset 'ALocalSymbol (lambda (x) (* 2 x)))
  (ALocalSymbol 4)
  )

评估此项将返回8.请注意ALocalSymbol(let ((ALocalSymbol))...)前面的引号。虽然setq引用了符号,但fset却没有。

flet是一种语法糖。使用普通的let来定义零值符号,允许您选择要设置的符号的“单元格”。您可以使用setq设置符号的值单元格,或使用fset设置功能单元格。

希望这有帮助,

巴勃罗