5

我正在使用 Norvig 的人工智能编程范式自学 Common Lisp,遇到了一些我不理解的东西,他也没有解释。

(defun mappend (fn the-list)
  (apply #'append (mapcar fn the-list)))

如下调用高阶函数和不higherOrderFunc #'funcName funcArg调用时他做了什么有什么区别?调用高阶函数时有必要吗 ?mapcar#'#'

4

3 回答 3

9

Common Lisp 对函数和变量有不同的命名空间。

(defun mappend (fn the-list)
   (apply #'append (mapcar fn the-list)))

上面MAPPEND用两个局部变量定义fnthe-list

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))
于 2013-04-10T22:32:44.793 回答
6

#'function:的语法糖,#'foo读作(function foo).

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

于 2013-04-10T22:25:31.943 回答
2

使用#'不是严格要求。相反,如果您只是传递'foo符号函数,则会被调用。考虑以下:

* (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 投票 [...] 允许 'function' 使用唯一的 'symbol' 或 'function' 类型;[...] 必须在 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)
于 2013-04-10T23:22:12.017 回答