为什么我必须 funcall 从另一个函数返回的函数?

Why must I funcall a function returned from another?

为什么这不起作用?

( ((lambda () (lambda (x) (funcall #'1+ x)))) 2)
 ; yields Compile-time error: illegal function call

我 运行 遇到过这样的情况,后来发现 funcall 解决了它,即

(funcall ((lambda () (lambda (x) (funcall #'1+ x)))) 2) ; => 3

我很困惑,因为它似乎第一个应该工作,因为我实际上有一个我正在调用的函数,而不仅仅是一个可能属于任一命名空间的符号(即 (type-of ((lambda () #'1+))) ; => FUNCTION)。我认为这有点像你不需要 funcall lambda,例如 ((lambda (x) x) :HI) ; => :HI。我错过了什么?

Common Lisp 的语法要求,每次您想通过以下类型的复合形式调用函数时:

(f a1 a2 ... an)

列表的第一个元素 f 必须是表示函数名称的符号,或者是表示 lambda 表达式 的列表,即(参见 manual):

lambda expression n. a list which can be used in place of a function name in certain contexts to denote a function by directly describing its behavior rather than indirectly by referring to the name of an established function; its name derives from the fact that its first element is the symbol lambda.

所以,这基本上意味着您不能将 returns 函数作为值的任何表达式作为第一个元素。在这些情况下,您必须使用 funcall.

因此,在您的第二个示例中,funcall 的第一个参数是 ((lambda () (lambda (x) (funcall #'1+ x)))),这是一个正确的复合形式,其中列表的第一个元素是 lambda 表达式 (lambda () (lambda (x) (funcall #'1+ x)))(应用于空参数列表)。

在第一个示例中,列表的第一个元素是一个返回函数的表达式,因此您必须使用 funcall.

Common Lisp 使用 form 这个词来表示所有可以被评估的东西。 形式

  • 一个符号喜欢foo
  • 一个复合形式,一个列表,见下​​文
  • 自评估对象(如数字、字符、数组、字符串...)。

一个复合形式

  • a 特殊形式 (<special-operator> ...)
  • a lambda 形式 喜欢 (lambda (...) ...)
  • 一个宏形式(<macroname> ...)
  • 函数形式 (<functionname> ...).

以上是一组复合形式。 ANSI Common Lisp 规范没有提供添加新类型表单或不同语法的方法。 EVALCOMPILE accept 等函数的接口是不可扩展的。

所以像

(((lambda (foo)
    (lambda (bar)
      (list foo bar)))
  1)
 2)

不是有效的 Common Lisp。这在 Common Lisp 中没有意义:

( <not a lambda form,
   not a special operator,
   not a macro name
   and not a function name>
2)

请注意,Common Lisp 允许 lambda 形式特殊运算符宏名称function 命名为复合形式中的第一个元素。但它允许变量并且允许其他复合形式作为复合形式的第一个元素。

表示这在 Common Lisp 中没有意义:

( <a function form> 2)

因此 ((foo 1) 2)(((foo 1) 2) 3)((((foo 1) 2) 3) 4)(((((foo 1) 2) 3) 4) 5) 在 Common Lisp 中是不合法的。你明白了。要调用从函数调用返回的函数对象,我们必须使用 (funcall (foo ...) ...)。这使得调用返回的函数对象比 ((foo ...) ...).

更明显

让我们为这个特性向Common Lisp的设计者致敬。否则我可能不得不查看以

开头的可能有意义的代码
(((((((((((( .....

而且很难弄清楚它的作用。基本上那将是只写代码。

你的问题

为什么我必须 funcall 从另一个返回的函数?

简短的回答:因为语法不允许其他方式,在 Common Lisp 中。

我已经阅读了这个article然后修改了我的代码如下:

(defparameter *my-fun* 1)

(defun my-func (v0)   
  (setf (symbol-function '*my-fun*)
    (lambda (v1)
      (+ v0 v1)))   
   '*my-fun*)

并且这样调用((my-func 2) 3),但是也报"illegal function call"。我认为我的代码符合 lambda 演算,但哪里错了。

在我看来,(my-func2)returns符号*my_fun*,而*my-fun*的函数单元格指向一个函数对象,所以((my-func 2) 3) => (*my-fun* 3) => ((lambda (v1) (+ 2 v1)) 3) => (+ 2 3) => 5

这有效:首先你的定义相同:

(defparameter *my-fun* 1)

(defun my-func (v0)   
  (setf (symbol-function '*my-fun*)
    (lambda (v1)
      (+ v0 v1)))   
   '*my-fun*)

但是,调用使用 funcall:

(funcall (my-func 2) 3)