我对CL有些陌生,目前正试图围绕mapcan
,#'
,funcall
和闭包。
这是一个闭包,它将谓词应用于数字 n ,如果正确,则返回(list n)
,否则nil
:
(defun all-those (predicate)
(lambda (n)
(if (funcall predicate n) (list n))))
我知道我需要调用funcall
来将此闭包转换为函数。这很好用:
> (funcall (all-those #'evenp) 8)
(8)
现在我尝试将以后创建的函数作为参数传递给mapcan:
> (mapcan #'(funcall (all-those #'evenp)) '(1 2 3 4))
我收到编译错误:(FUNCALL (ALL-THOSE #'EVENP)) is not a legal function name
但是如果我省略#'
以及funcall:
> (mapcan (all-those #'evenp) '(1 2 3 4))
(2 4)
现在我很困惑。我的理解是,当使用mapcan
来跟随符号的函数绑定(*)时我需要使用函数来引用函数,并且当“关闭闭包”时我需要调用funcall
。
是因为#'
和funcall
相互抵消,还是为什么我必须在上面的示例中省略它们?提前感谢您的回复。
(*)我知道在这个例子中我没有一个可以遵循其功能绑定的符号。但是,如果我使用匿名函数mapcan
,我仍需要引用它:(mapcan #'(lambda ...
答案 0 :(得分:5)
要 mapcar , funcall 等,您需要传递函数对象或符号。如果传递符号,则符号的符号函数将用作函数。如果传递函数对象,则将其用作函数。
您的所有函数返回一个函数。这意味着(mapcan(所有那些......)......)很好。
尖锐的引用(#' )只是功能表单的简写。也就是说,#' foo 与(function foo)相同:
function 的值是当前名称的功能值 词汇环境。
如果name是函数名,则该名称的功能定义是 由最内部的词汇封闭的flet,标签或者 macrolet表单,如果有的话。否则全球功能 返回函数名称的定义。
如果name是lambda表达式,则返回词法闭包。在 可能存在同一组绑定的闭包的情况 不止一次产生,各种产生的闭合可能或可能 不是等式。
因此,您只能将#' 或功能与功能名称一起使用。这意味着符号(例如,#' car )或lambda表达式(例如,#'(lambda(x)x))。这意味着以下内容不起作用(或者甚至是有意义的):
#'(funcall (all-those #'evenp))
现在我很困惑。据我所知,我需要引用一句话 使用mapcan跟随符号的功能绑定时的功能(*) 并且我需要在"关闭一个闭包时调用funcall。
mapcar, etc.,的文档说它的第一个参数是:
功能---一个必须占用多少功能的指示符 参数有列表。
来自术语表:
function designator n。功能的指示符;也就是说,一个对象 表示一个函数,它是以下之一:符号(表示 在全局环境中由该符号命名的函数,或者a 功能(表示自己)。如果符号,后果是不确定的 用作函数指示符,但它没有全局 定义为函数,或者它具有宏或全局定义 一种特殊的形式。另请参见扩展函数指示符。
所以,你可以直接将一个函数传递给 mapcar , funcall 等,这正是你所做的:
(mapcan (all-those …) …)
你也可以这样做:
(mapcan (lambda (x) ...) ...)
(mapcan #'(lambda (x) ...) ...)
(mapcan 'car ...)
(mapcan #'car ...)
(mapcan (symbol-function 'car) ...)
答案 1 :(得分:4)
<强>摘要强>
(function foo)
是一种特殊形式,返回一个函数对象。这里从名称foo
中检索。我们用它来获取一个函数对象。
(funcall foo)
用于调用作为参数传递的函数 - 这里是foo
的变量值。
funcall = FUNction CALL =调用函数。
我们用它来调用一个函数对象。
<强>详情
这是一个闭包,它将谓词应用于数字n,如果正确,则返回(列表n),否则为nil:
(defun all-those (predicate) (lambda (n) (if (funcall predicate n) (list n))))
不,那不是关闭。 all-those
返回一个闭包,但它本身不是一个闭包。
? #'all-those
#<Compiled-function ALL-THOSE #x302000C9631F>
? (all-those #'evenp)
#<COMPILED-LEXICAL-CLOSURE (:INTERNAL ALL-THOSE) #x302000E5ECFF>
我知道我需要调用funcall将这个闭包变成一个函数。
闭包是一个函数对象。
? (functionp (all-those #'evenp))
T
注意:所有闭包也是函数对象。并非所有函数对象都是闭包。
闭包是一个函数和关联的变量绑定。它是一个功能对象。
请注意,匿名函数不一定是闭包。 (function (lambda () ()))
不返回闭包,因为没有变量绑定。你可以说它是一个带有空绑定的闭包,但在CL说它不叫闭包。
请注意,在标准Common Lisp中,无法确定函数对象是否实际上是一个闭包,并且无法通过变量名访问其绑定。
我知道我需要调用funcall将这个闭包变成一个函数。
funcall
用于通过参数调用函数对象(或将从符号的函数值中检索的函数对象)。
请记住,有多种方法可以调用函数:
调用命名的全局函数:(foo bar baz)
调用一个名为lexical的函数:(foo bar bar)
通过符号(funcall 'foo bar baz)
从变量值调用函数对象:(funcall foo bar baz)
从函数名称(词法或全局)调用函数对象:(funcall #'foo bar baz)
调用匿名函数对象:(funcall (function (lambda (foo) foo)) 'bar)
或(funcall #'(lambda (foo) foo) 'bar)
或(funcall (lambda (foo) foo) 'bar)
调用匿名函数:((lambda (foo) foo) 'bar)
然后有APPLY
类似于FUNCALL
但从列表中获取参数。
(apply #'+ 1 2 3 (list 4 5 6)) is similar to (funcall #'+ 1 2 3 4 5 6)
FUNCALL 本身就是一个功能。将评估其所有参数形式。第一个参数需要求值为符号或函数对象。 funcall
将使用参数调用函数对象(或从符号的函数值中检索的函数对象。
功能是一个特殊的运算符。这是语法。它本身不是一个功能。 FUNCTION
期望符号或lambda表达式作为其子表单。 FUNCTION
形式返回一个函数对象,对应于符号(来自全局函数或词法函数)或 lambda表达式。
? (defun foo (bar) (list bar 'baz))
FOO
? (function foo) ; a function object from the global function
#<Compiled-function FOO #x302000CC0D1F>
? #'foo ; the same, differently written
#<Compiled-function FOO #x302000CC0D1F>
? (funcall #'foo 42) ; calling the function object
(42 BAZ)
? (funcall 'foo 42) ; calling the symbol-function of the symbol
(42 BAZ)
? (funcall (symbol-function 'foo) 42) ; as above
(42 BAZ)
? (flet ((foo (arg) (list arg :foo))) ; a local lexical function
(list (foo 43) ; calling the local lexical function
(funcall #'foo 42) ; calling a function object,
; from the local lexical function
(funcall 'foo 41))) ; calling the symbol-function of the symbol
((43 :FOO) (42 :FOO) (41 BAZ))