为什么我必须 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 规范没有提供添加新类型表单或不同语法的方法。 EVAL
或 COMPILE
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)
为什么这不起作用?
( ((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 规范没有提供添加新类型表单或不同语法的方法。 EVAL
或 COMPILE
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)