Elisp:在 Let 中绑定一个 lambda 并执行它
Elisp: Bind a lambda in a Let and execute it
我试图理解 Emacs Lisp 中的 lambda
概念。
在ielm
中执行:
((lambda (x) (* x x)) 5)
给我们 25
,
(let ((x 4)) (* x x))
给我们 16
。但是当我这样做时:
(let ((f (lambda (x) (* x x)))) (f 7))
它没有给我 49
,而是通知我:
*** Eval error *** Symbol's function definition is void: f
不知道为什么,我确信语法是正确的并且 f 定义在 let
?
使用cl-flet
定义let
-ed函数
我们可以不使用funcall
实际上做到这一点。 cl
模块包括来自 Common Lisp 的标准函数。我们先导入它:
(require 'cl)
之后我们可以使用cl-flet
来定义我们的函数:
(cl-flet ((f (x) (* x x)))
(f 7))
如果这不是重复的,我会感到惊讶,但我无法在 Stack Overflow 上轻松找到它。在 "Lisp-2" 语言(例如 Emacs Lisp 和 Common Lisp)中,函数和变量有单独的名称space。函数调用如下所示:
((lambda ...) ...) ; call the lambda function
或
(f ...) ; call the function binding of f
如果你想调用的函数是一个变量的值,那么你需要使用funcall或者apply:
(apply f ...)
(funcall f ...)
apply 和 funcall 之间的区别在其他地方有详细记录,但快速的区别是 apply 需要参数列表(在某些 Lisp 中,"spreadable argument list"),而 funcall 直接接受参数。例如,
(let ((f (lambda (a b) (+ a b))))
(funcall f 1 2) ; arguments directly
(apply f '(1 2))) ; arguments in a list
在 "Lisp-1" 中(如 Scheme),您不需要 funcall,因为只有一个 space 用于绑定。在 Scheme 中你可以做:
(let ((f (lambda (a b) (+ a b))))
(f 1 2))
Lisp-1 和 Lisp-2 语言之间的差异在 What is the difference between Lisp-1 and Lisp-2? 中有更多描述。最大的区别是当系统看到函数调用时,它如何确定要调用的函数。在 Lisp-1 中,变量有值,仅此而已。所以当系统看到类似:
(f ...)
f是一个变量,唯一可以调用的就是f的值。在 Lisp-2 中,系统尝试调用 f 的 函数值 ,这与 变量 [=46] 的值没有任何关系=] f。起初这可能有点令人困惑,但在很多情况下它实际上非常方便,因为它使得意外地混淆具有通用名称的函数变得更加困难。例如,在 Lisp-1 中,你会看到很多人使用 lst
作为参数名称而不是 list
,因为如果他们将参数命名为 list
,那么他们就不能在函数中使用(标准)函数 list
。
我试图理解 Emacs Lisp 中的 lambda
概念。
在ielm
中执行:
((lambda (x) (* x x)) 5)
给我们 25
,
(let ((x 4)) (* x x))
给我们 16
。但是当我这样做时:
(let ((f (lambda (x) (* x x)))) (f 7))
它没有给我 49
,而是通知我:
*** Eval error *** Symbol's function definition is void: f
不知道为什么,我确信语法是正确的并且 f 定义在 let
?
使用cl-flet
定义let
-ed函数
我们可以不使用funcall
实际上做到这一点。 cl
模块包括来自 Common Lisp 的标准函数。我们先导入它:
(require 'cl)
之后我们可以使用cl-flet
来定义我们的函数:
(cl-flet ((f (x) (* x x)))
(f 7))
如果这不是重复的,我会感到惊讶,但我无法在 Stack Overflow 上轻松找到它。在 "Lisp-2" 语言(例如 Emacs Lisp 和 Common Lisp)中,函数和变量有单独的名称space。函数调用如下所示:
((lambda ...) ...) ; call the lambda function
或
(f ...) ; call the function binding of f
如果你想调用的函数是一个变量的值,那么你需要使用funcall或者apply:
(apply f ...)
(funcall f ...)
apply 和 funcall 之间的区别在其他地方有详细记录,但快速的区别是 apply 需要参数列表(在某些 Lisp 中,"spreadable argument list"),而 funcall 直接接受参数。例如,
(let ((f (lambda (a b) (+ a b))))
(funcall f 1 2) ; arguments directly
(apply f '(1 2))) ; arguments in a list
在 "Lisp-1" 中(如 Scheme),您不需要 funcall,因为只有一个 space 用于绑定。在 Scheme 中你可以做:
(let ((f (lambda (a b) (+ a b))))
(f 1 2))
Lisp-1 和 Lisp-2 语言之间的差异在 What is the difference between Lisp-1 and Lisp-2? 中有更多描述。最大的区别是当系统看到函数调用时,它如何确定要调用的函数。在 Lisp-1 中,变量有值,仅此而已。所以当系统看到类似:
(f ...)
f是一个变量,唯一可以调用的就是f的值。在 Lisp-2 中,系统尝试调用 f 的 函数值 ,这与 变量 [=46] 的值没有任何关系=] f。起初这可能有点令人困惑,但在很多情况下它实际上非常方便,因为它使得意外地混淆具有通用名称的函数变得更加困难。例如,在 Lisp-1 中,你会看到很多人使用 lst
作为参数名称而不是 list
,因为如果他们将参数命名为 list
,那么他们就不能在函数中使用(标准)函数 list
。