我对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
跟随符号的函数绑定(bind)(*)时,我需要对函数进行加引号,并且在“关闭闭包”时需要调用funcall
。是因为
#'
和funcall
互相抵消了,还是在上面的示例中为什么我必须忽略它们呢?预先感谢您的任何答复。(*)我知道在此示例中,我实际上没有一个可以遵循功能绑定(bind)的符号。但是,如果我使用匿名函数和
mapcan
,我仍然需要对其加引号:(mapcan #'(lambda ...
最佳答案
要传递 mapcar , funcall 等,您需要传递函数对象或符号。如果传递符号,则将符号的符号功能用作功能。如果传递函数对象,则将其用作函数。
您的所有这些函数将返回一个函数。这意味着(mapcan(所有这些…)…)很好。
引号(#')只是函数形式的简写。也就是说,#'foo 与(函数foo)相同:
因此,您只能将#'或函数与函数名称一起使用。这意味着符号(例如#'car )或lambda表达式(例如#'(lambda(x)x))。这意味着以下操作不起作用(甚至说不通):
#'(funcall (all-those #'evenp))
mapcar, etc.,的文档说它的第一个参数是:
从词汇表:
因此,您可以将函数直接传递给 mapcar , funcall 等,这正是您在执行的操作:
(mapcan (all-those …) …)
您还可以执行以下操作:
(mapcan (lambda (x) ...) ...)
(mapcan #'(lambda (x) ...) ...)
(mapcan 'car ...)
(mapcan #'car ...)
(mapcan (symbol-function 'car) ...)