Elisp:在Let中绑定一个lambda并执行它

Tah*_*san 4 lisp emacs elisp

我试图理解lambdaEmacs Lisp中发现的概念.

ielm,执行:

((lambda (x) (* x x)) 5)
Run Code Online (Sandbox Code Playgroud)

给了我们25,和

(let ((x 4)) (* x x))
Run Code Online (Sandbox Code Playgroud)

给了我们16.但是,当我这样做时:

(let ((f (lambda (x) (* x x)))) (f 7))
Run Code Online (Sandbox Code Playgroud)

它没有给我49,而是通知我:

*** Eval error ***  Symbol's function definition is void: f
Run Code Online (Sandbox Code Playgroud)

不知道为什么,我确定语法是正确的,f是在let?中定义的?

使用cl-flet定义let-ed功能

我们可以真正做到这一点,而无需使用funcall.该cl模块包括Common Lisp的标准功能.我们先导入它:

(require 'cl)
Run Code Online (Sandbox Code Playgroud)

此后我们可以cl-flet用来定义我们的功能:

(cl-flet ((f (x) (* x x)))
  (f 7))
Run Code Online (Sandbox Code Playgroud)

Jos*_*lor 9

如果这不是重复,我会感到惊讶,但我在Stack Overflow上找不到它.在"Lisp-2"语言(例如,Emacs Lisp和Common Lisp)中,函数和变量有单独的名称空间.函数调用如下所示:

((lambda ...) ...) ; call the lambda function
Run Code Online (Sandbox Code Playgroud)

要么

(f ...) ; call the function binding of f
Run Code Online (Sandbox Code Playgroud)

如果要调用作为变量值的函数,则需要使用funcall或apply:

(apply f ...)

(funcall f ...)
Run Code Online (Sandbox Code Playgroud)

applyfuncall之间的区别在其他地方有很好的记录,但快速区别在于apply需要一个参数列表(在一些Lisp中,一个"可扩展的参数列表"),而funcall直接接受参数.例如,

(let ((f (lambda (a b) (+ a b))))
  (funcall f 1 2)      ; arguments directly
  (apply f '(1 2)))    ; arguments in a list
Run Code Online (Sandbox Code Playgroud)

在"Lisp-1"中,(如Scheme),您不需要funcall,因为只有一个空间可用于绑定.在Scheme中你可以做到:

(let ((f (lambda (a b) (+ a b))))
  (f 1 2))
Run Code Online (Sandbox Code Playgroud)

Lisp-1和Lisp-2 之间的区别更多描述Lisp-1和Lisp-2有什么区别?.最大的区别在于系统何时看到函数调用,它如何确定要调用的函数.在Lisp-1中,变量具有值,而这就是全部.所以当系统看到类似的东西时:

(f ...)
Run Code Online (Sandbox Code Playgroud)

f是一个变量,唯一可以调用的是f的值.在Lisp-2中,系统试图调用f 的函数值,f 函数值不必与变量 f 的值有任何关系.起初这可能有点令人困惑,但在许多情况下它实际上非常方便,因为它使得用常见名称意外地模糊函数变得更加困难.例如,在Lisp-1中,你会看到许多人使用lst参数名而不是list,因为如果他们命名参数list,那么他们就不能在函数中使用(标准)list函数.