Fra*_*ank 4 syntax lambda common-lisp
函数位置的lambda表达式编译得很好:
> ((lambda (n) (> n 10)) 42)
T
Run Code Online (Sandbox Code Playgroud)
另一方面:
> (defun greater-than (x)
(lambda (n) (> n x)))
GREATER-THAN
> ((greater-than 10) 42)
Compile-time error: illegal function call
Run Code Online (Sandbox Code Playgroud)
不起作用.
(我显然需要打电话FUNCALL让它工作:(funcall (greater-than 10) 42)=> T.
我理解为什么带有函数对象作为值绑定的SYMBOL 必须不起作用,例如:(let ((foo (lambda () 42))) (foo)).单独的命名空间和所有这些.
但为什么禁止功能对象本身在功能位置?这个决定背后的理由是什么?
什么是lambda形式?
函数位置的lambda形式编译得很好:
在Common Lisp中,lambda表达式不是一种形式.具有lambda表达式和零个或多个参数的列表是一个表单,特别是一个lambda表单.可以评估表单,而不是lambda表达式.注意:还有一个宏运算符lambda,它使用特殊运算符将宏表单 扩展(lambda ...)为(function (lambda ...))- 这是一个有效的表单. function
( ; the whole list is a valid lambda form
(lambda (n) (> n 10)) ; a lambda expression, not a form
42) ; 42 is a form, too
Run Code Online (Sandbox Code Playgroud)
上面的lambda形式大致类似于:
(let ((n 42))
(> n 10))
Run Code Online (Sandbox Code Playgroud)
在运行时调用评估结果的函数对象
但为什么禁止功能对象本身在功能位置?这个决定背后的理由是什么?
Common Lisp更喜欢在函数位置具有已知(或未知)的函数.
(sin 3)
((lambda (x) (sin 3)) 3)
(unknown-function 3)
Run Code Online (Sandbox Code Playgroud)
最重要的是,三个函数不能是其他函数:它们不能是数字,字符串或其他数据对象.没有办法在那里放置另一个数据对象.运营商如DEFUN,FLET和其他人拒绝定义功能,这是其他一些数据类型(数字,字符串,...).
如果我们在函数位置进行计算,我们可以写:
((if (> foo bar) 42 #'sin) 3)
Run Code Online (Sandbox Code Playgroud)
根据(> foo bar)对此的评估可能类似于(sin 3)或者(42 3),后者不是有效形式,因为数字不是函数.
Common Lisp的需要一个明确使用的一个FUNCALL,APPLY,MULTIPLE-VALUE-CALL调用函数对象.这使得在源代码中清楚地表明正在计算/检索和调用函数对象.他们还做了必要的检查,事实上传递的东西确实是一个函数或表示函数的符号.
背景
有关详细信息,请参阅Gabriel/Pitman的"功能单元和值单元中的分离技术问题".
大多数情况下,"历史原因",即实现问题,但在功能和值命名空间的分离方面,它在语义上也不明显.操作员位置中的表单被评估为其功能值.只有符号具有函数值.
Lambda表格是一个特例; 您可以想象它们在函数和值命名空间中求值.然而,这实际上并不正确,只是近似/合理化.
当我年轻的时候,我想象应该有一个读取器宏镜像#',例如#^,这样你就可以将某些东西"拉"到函数命名空间中,就像你将某些东西"拉"到值命名空间中一样#'.但是,它只会扩展到funcall:
(#^(make-adder 5) 3) ≡ (funcall (make-adder 5) 3)
我现在非常不愿意为这种无聊的用途引入读者宏.放松,只需使用funcall,它最终确实非常好用.