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

时间:2016-05-02 09:02:12

标签: common-lisp lisp-2

为什么这不起作用?

( ((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。我错过了什么?

4 个答案:

答案 0 :(得分:6)

Common Lisp使用 form 这个词来表示可以评估的所有内容。 表单

  • 符号,如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)(((foo 1) 2) 3)((((foo 1) 2) 3) 4)(((((foo 1) 2) 3) 4) 5)在Common Lisp中不合法。你明白了。要调用函数调用返回的函数对象,我们必须使用(funcall (foo ...) ...)。这使得调用返回的函数对象比((foo ...) ...)更明显。

让我们赞扬Common Lisp的设计者这个功能。否则,我可能需要查看以

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

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

您的问题

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

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

答案 1 :(得分:5)

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

(f a1 a2 ... an)

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

  

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

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

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

在第一个示例中,您将列表中的第一个元素作为返回函数的表达式,因此您必须使用(lambda () (lambda (x) (funcall #'1+ x)))

答案 2 :(得分:0)

我已阅读此article,然后修改了我的代码:

(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)=&gt; (* my-fun * 3)=&gt; ((lambda(v1)(+ 2 v1))3)=&gt; (+ 2 3)=&gt; 5

答案 3 :(得分: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)