mapcan,尖锐的报价和闭包

时间:2016-11-10 21:32:07

标签: closures common-lisp funcall

我对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 ...

2 个答案:

答案 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))