我正在使用Norvig的人工智能编程范例来教授自己的Common Lisp,并且遇到了一些我不理解的事情,他没有解释。
(defun mappend (fn the-list)
(apply #'append (mapcar fn the-list)))
如下调用高阶函数,higherOrderFunc #'funcName funcArg
和在没有mapcar
调用#'
时他做了什么有什么区别?调用高阶函数时需要#'
吗?
答案 0 :(得分:8)
Common Lisp具有不同的函数和变量名称空间。
(defun mappend (fn the-list)
(apply #'append (mapcar fn the-list)))
上面MAPPEND
定义了两个局部变量fn
和the-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))
答案 1 :(得分:6)
#'
是function
的语法糖:#'foo
被视为(function foo)
。
Function
是一个特殊的运算符,它返回绑定到给定名称的函数值。如果将函数作为参数传递,则该参数(在您的情况下为fn
)将其值绑定到函数。要将其传递给另一个函数,您只需将变量名称放入调用表单即可。但是,要获取名称的函数值,您需要使用function
。
答案 2 :(得分: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)
Practially#'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)