公共Lisp中的高阶函数语法

公共Lisp中的高阶函数语法,lisp,common-lisp,Lisp,Common Lisp,我在用诺维格的人工智能编程范例自学CommonLisp,遇到了一些我不懂的东西,他也没有解释 (defun mappend (fn the-list) (apply #'append (mapcar fn the-list))) 按如下方式调用高阶函数,higherOrderFunc#'funcName funcArg与他在调用mapcar时不使用#'时所做的操作有什么区别?调用高阶函数时是否需要#' #'是函数的语法糖:#'foo读作(函数foo) Function是一个特殊的运算符,返

我在用诺维格的人工智能编程范例自学CommonLisp,遇到了一些我不懂的东西,他也没有解释

(defun mappend (fn the-list)
  (apply #'append (mapcar fn the-list)))
按如下方式调用高阶函数,
higherOrderFunc#'funcName funcArg
与他在调用
mapcar
时不使用
#'
时所做的操作有什么区别?调用高阶函数时是否需要
#'

#'
函数
的语法糖:
#'foo
读作
(函数foo)


Function
是一个特殊的运算符,返回绑定到给定名称的函数值。如果将函数作为参数传递,则该参数(在您的示例中为,
fn
)的值将绑定到该函数。要将其传递给另一个函数,只需将变量名放入调用表单中即可。但是,要获取名称的函数值,需要使用
function

访问它。Common Lisp具有不同的函数和变量名称空间

(defun mappend (fn the-list)
   (apply #'append (mapcar fn the-list)))
上面的
MAPPEND
使用两个局部变量
fn
列表定义

APPLY
获取
APPEND
的函数值

MAPCAR
获取
FN的变量值

类似的例子如下:

CL-USER 129 >  (flet ((add-something (number)
                       (+ number 17)))
                (let ((add-something (lambda (number)
                                       (+ number 42))))
                  (list
                   (mapcar #'add-something '(1 2 3))
                   (mapcar add-something '(1 2 3)))))

->

((18 19 20) (43 44 45))
LET
创建局部变量,
FLET
创建局部函数

第一个
mapcar
使用函数名称空间,第二个使用变量名称空间

Common Lisp使用一个特殊的函数名称空间,因为它被认为效率更高(实现快速Lisp稍微容易一点),并且允许函数和变量具有相同的名称

在Common Lisp中,我们可以编写:

(defun list-me (list)
  (list list))
在没有单独名称空间的Scheme中,可以编写如下内容:

(define (list-me lst)
  (list lst))
使用
#“
并不是严格要求的。如果只是传递
'foo
,将调用symbol函数。考虑以下事项:

* (defvar foo #'(lambda (a) 'var))
* (setf (symbol-function 'foo) #'(lambda (a) 'fun))

* (mapcar 'foo '(a b))
(FUN FUN)

* (mapcar #'foo '(a b))
(FUN FUN)

* (mapcar foo '(a b))
(VAR VAR)
实际上,“foo”或“foo”是等效的:

X3J13投票[…]只允许“符号”类型的“功能” 或"功能";;[…]必须使用“函数”特殊形式[…] 在lambda表达式[…]之前

flet
中的函数规范具有一些有趣的特性:

* (flet ((foo (a) 'FLET))
    (mapcar foo '(a b)))           ; Uses 'value' of foo
(VAR VAR)

* (flet ((foo (a) 'FLET))
    (mapcar 'foo '(a b)))          ; Uses 'function' of foo
(FUN FUN)

* (flet ((foo (a) 'FLET))
    (mapcar #'foo '(a b)))         ; Uses local binding 'flet' of foo
(FLET FLET)

你能解释一下“flet”的用法以及它与“let”的区别吗?似乎是用“let”定义某个临时变量的范围的方式来定义某个临时函数的范围。为了澄清其中隐含的一点,Rainer的回答中增加了一个小小的补充:当调用
mappend
时,需要将函数参数作为
#some-func
传递。获取符号
some func
的函数值,然后将其作为
fn
的值传递到
mappend
#'foo
'foo
并不等同于
(函数foo)
(引用foo)
。也就是说,即使它们可以在某些相同的情况下使用,也不是很好。无论哪种方式,使用带引号的符号都会模糊代码的含义,而不是本地函数<代码>(flet((foo()'bar))(funcall'foo))
不起作用。此外,在使用优化编译器时,
(funcall(函数栏))
和(funcall'bar))之间可能会有细微的差异。后者可能总是通过符号查找函数,而前者可能会看到查找被优化,并在编译期间使用当前函数绑定。文件编译器可能希望这样做。因此:为了保持一致,最好使用
函数
#'
。如果需要全局函数的后期绑定,请使用符号。更新为
flet
use。注意:我同意使用
#“
,但我的选择不是OQ中要求的。