4

为什么这不起作用?

( ((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)的符号。我认为这有点像你不需要lambdafuncall例如((lambda (x) x) :HI) ; => :HI. 我错过了什么?

4

4 回答 4

6

Common Lisp 使用单词形式来表示所有可以评估的东西。表格是_

  • 像这样的符号foo
  • 复合形式,列表,见下​​文
  • 自评估对象(如数字、字符、数组、字符串……)。

复合形式是

  • 一种特殊的形式 (<special-operator> ...)
  • 像这样的lambda 形式(lambda (...) ...)
  • 形式 (<macroname> ...)
  • 函数形式 (<functionname> ...)

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

所以像

(((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 形式特殊运算符宏名称函数名称作为复合形式中的第一个元素。但它不允许变量,也不允许其他复合形式作为复合形式中的第一个元素。

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

( <a function form> 2)

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

让我们为这个功能点赞 Common Lisp 的设计者。否则我可能不得不查看可能有意义的代码

(((((((((((( .....

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

你的问题

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

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

于 2016-05-02T11:44:06.137 回答
5

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

(f a1 a2 ... an)

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

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

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

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

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

于 2016-05-02T09:25:58.213 回答
0

我已经阅读了这篇文章,然后在下面修改了我的代码:</p>

(defparameter *my-fun* 1)

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

并以这种方式调用它((my-func 2) 3),但它也报告“非法函数调用”。我认为我的代码与 lambda 演算保持一致,但哪里错了。

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

于 2017-02-09T01:33:30.383 回答
0

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

(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)
于 2018-08-06T15:05:31.693 回答