Emacs Lisp:为什么此sexp会导致无效功能错误? [英] Emacs lisp: why does this sexp cause an invalid-function error?

查看:136
本文介绍了Emacs Lisp:为什么此sexp会导致无效功能错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有问题的性爱是

(((lambda (b)
  (lambda (a)
    (+ b a))) 3) 5)

在我看来,

应该看起来应该是8,而在其他形式(例如球拍)中却可以,但在elisp中却抛出了该错误:

which, to me, looks like it should evaluate to 8, and in other lisps (e.g. Racket) it does, but in elisp it instead throws this error:

Debugger entered--Lisp error: (invalid-function ((lambda (b) (lambda (a) (+ b a))) 3))

似乎是在告诉我

((lambda (b)
  (lambda (a)
    (+ b a))) 3)

不是有效的函数.这似乎是错误的,因为当我评估该表达式时,我得到了

Is not a valid function. This seems wrong, because when I evaluate that expression I get

(lambda (a) (+ b a))

对我来说似乎是一个有效的功能.有谁知道为什么会这样吗?它与动态作用域有关吗?

which looks like a valid function to me. Does anyone have any idea why this happens? Does it have something to do with dynamic scoping?

推荐答案

这里有两个问题.正如其他答案所指出的,第一个问题是语法问题.问题中提到的第二个问题是范围界定问题.

There are two issues here. The first is a matter of syntax, as other answers have pointed out. The second, which is mentioned in the question, is a matter of scoping issues.

在Emacs Lisp(和 Lisp-2 系列),函数调用类似于(f args...),其中f是具有函数值的符号或

In Emacs Lisp (and other Lisps in the Lisp-2 family), a function call looks like (f args...) where f is a either a symbol that has a function value, or a lambda expression. For instance,

(list 1 2 3)  
=> (1 2 3)

因为list具有功能绑定.另外,

because list has a function binding. Also,

((lambda (x y) (list x x y y)) 1 2)
=> (1 1 2 2)

因为(lambda (x y) (list x x y y))lambda表达式.但是,您不能做的事就是使用其中的一个值作为函数的值.

because (lambda (x y) (list x x y y)) is a lambda expression. What you can't do, though, is use something the value of which of is a function.

(let ((id (lambda (x) x)))
  (id 3))

发出一个Lisp error: (void-function id)信号.但是我们可以使用funcall:

signals a Lisp error: (void-function id). But we can call function values using funcall:

(let ((id (lambda (x) x)))
  (funcall id 3))
=> 3

注意:这是一种比较好的观察方法,但实际上情况要复杂一些.参见 9.2种形式详细信息和一些深奥的内容,例如函数间接性.

Note: That's a reasonably good way of looking at it, but in fact things are a little more complicated. See 9.2 Kinds of Forms in the manual for the details and esoteric bits such as function indirection.

因此,现在我们可以解决语法问题.重新格式化以表明哪些函数正在获取哪些参数的原始代码为:

So, now we can address the syntax issue. The original code, reformatted a bit to indicate which functions are getting which arguments, is:

(((lambda (b)
    (lambda (a)
      (+ b a)))
  3)
 5)

据我了解,其目的是首先使用参数3调用(lambda (b) ...)以返回匿名函数(lambda (a) ...).在Emacs Lisp中,应该是:

As I understand it, the intent is to first call (lambda (b) ...) with the argument 3 to get back an anonymous function, (lambda (a) ...). In Emacs Lisp that would be:

((lambda (b)
   (lambda (a)
     (+ b a)))
 3)
=> (lambda (a) (+ b a))

现在,您还想使用5调用返回的匿名函数.我们使用funcall来做到这一点:

Now, you also want to call the returned anonymous function with 5. We use funcall to do that:

(funcall ((lambda (b)
            (lambda (a)
              (+ b a)))
          3)
         5)

范围问题

令人失望的是,这段代码生成了Lisp error: (void-variable b). 是我们最终遇到动态范围界定和词汇范围界定的地方.由于变量b是动态绑定的,因此其值不会保留在匿名函数(lambda (a) (+ b a))中.我们可以通过将整个窗体包围在绑定了b的东西中,然后查看会发生什么来检查是否发生了这种情况:

The Scoping Issue

Disappointingly, this code produces a Lisp error: (void-variable b). This is where we finally run into the issue of dynamic versus lexical scoping. Because the variable b was bound dynamically, its value is not preserved in the anonymous function (lambda (a) (+ b a)). We can check to see that this is what's happening by surrounding the whole form in something that binds b and seeing what happens:

(let ((b 100))
  (funcall ((lambda (b)
              (lambda (a)
                (+ b a)))
            3)
           5))
=> 105

我不是Emacs Lisp骇客,所以我不确定在Emacs中获取词法闭包的最好方式.我读到Emacs 24有它,但是我仍然在这里23.不过,基于此答案,我们可以使用lexical-let来获得所需的结果:

I'm not much of an Emacs Lisp hacker, so I'm not sure of the best way to get lexical closures in Emacs. I read that Emacs 24 has it, but I'm still on 23 here. Based on this answer, though, we can use lexical-let to get the results we need:

(funcall ((lambda (b)
            (lexical-let ((b b))
              (lambda (a)
                (+ b a))))
          3)
         5)
=> 8

lexical-let建立我们所需的词汇绑定,以便匿名函数(lambda (a) ...)确实将3插入其中.更具体地说,我们引入了b的词法绑定,而(lambda (a) …)引用的是该词法绑定.实际上,如果我们现在看一下返回的匿名函数,它不仅是(lambda (a) (+ b a)),而且是以更复杂(且不太有用)的方式打印的:

lexical-let establishes the lexical binding that we need, so that the anonymous function (lambda (a) ...) does have that 3 stuck into it. More specifically, we introduced a lexical binding of b, and it is that lexical binding that (lambda (a) …) references. In fact, if we look at the returned anonymous function now, it's not simply (lambda (a) (+ b a)), but is printed in a more complex (and less useful) way:

((lambda (b)
   (lexical-let ((b b))
     (lambda (a)
       (+ b a))))
 3)
=> (lambda (&rest --cl-rest--) (apply (lambda (G27322 a) (+ ... a)) (quote --b--) --cl-rest--))

顺便说一句,与词法绑定的变量b与动态绑定的b具有相同的名称并不重要;我们本可以使用(lexical-let ((c b)) ... (+ c a) ...)来代替.

As an aside, it doesn't matter that the lexically-bound variable b has the same name as the dynamically bound b; we could have used (lexical-let ((c b)) ... (+ c a) ...), instead.

这篇关于Emacs Lisp:为什么此sexp会导致无效功能错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆