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

Mas*_*tic 3 common-lisp lisp-2

为什么这不起作用?

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

我遇到了这样的情况,后来发现它funcall修复了它,即

(funcall ((lambda () (lambda (x) (funcall #'1+ x)))) 2) ; => 3
Run Code Online (Sandbox Code Playgroud)

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

Rai*_*wig 6

Common Lisp将单词form用于可以评估的所有内容.甲形式或者是

  • 像一个符号foo
  • 一个化合物形式,列表,请参见下面
  • 或者自我评估对象(如数字,字符,数组,字符串......).

化合物形式或者是

  • 一种特殊的形式 (<special-operator> ...)
  • 像一个lambda形式(lambda (...) ...)
  • 一个宏观形式 (<macroname> ...)
  • 功能表格 (<functionname> ...).

以上是复合形式的集合.ANSI Common Lisp规范无法添加新类型的表单或不同的语法.形成函数EVALCOMPILE接受的接口是不可扩展的.

所以像

(((lambda (foo)
    (lambda (bar)
      (list foo bar)))
  1)
 2)
Run Code Online (Sandbox Code Playgroud)

是无效的Common Lisp.这在Common Lisp中没有意义:

( <not a lambda form,
   not a special operator,
   not a macro name
   and not a function name>
2)
Run Code Online (Sandbox Code Playgroud)

请注意,Common Lisp允许将lambda表单,特殊运算符,宏名称函数名称作为复合形式的第一个元素.但它并没有允许的变量,它并没有允许其它化合物形式如在化合物形式的第一元件.

意味着这在Common Lisp中没有意义:

( <a function form> 2)
Run Code Online (Sandbox Code Playgroud)

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

让我们赞扬Common Lisp的设计者为这个功能.否则,我可能不得不看一下可能有意义的代码

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

并且很难弄清楚它的作用.基本上这将是只写代码.

你的问题:

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

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


Ren*_*nzo 5

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

(f a1 a2 ... an)
Run Code Online (Sandbox Code Playgroud)

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

lambda表达式 Ñ.可以在某些上下文中用来代替函数名列表,通过直接描述其行为来表示函数,而不是通过引用已建立函数的名称来间接地表示函数 ; 它的名字来源于它的第一个元素是符号 lambda.

因此,这基本上意味着您不能将任何将函数作为值返回的表达式作为第一个元素.在这种情况下,你必须使用funcall.

所以,在你的第二个例子中,funcallis 的第一个参数((lambda () (lambda (x) (funcall #'1+ x))))是一个正确的coumpound形式,其中列表的第一个元素是lambda表达式(lambda () (lambda (x) (funcall #'1+ x)))(应用于一个空的参数列表).

在第一个示例中,您将列表中的第一个元素作为返回函数的表达式,以便您必须使用funcall.