2013-04-10 93 views
4

我自学的是使用Norvig的AI编程范式的Common Lisp,遇到了一些我不明白的东西,他也没有解释。Common Lisp中的高阶函数语法

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

是什么叫高阶函数如下,higherOrderFunC#'funcName funcArg并呼吁mapcar没有#'时,他做什么区别呢?调用高阶函数时需要#'吗?

回答

8

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

在计划,它没有单独的名称空间一个会写这样的事:

(define (list-me lst) 
    (list lst)) 
+0

你能解释一下使用“FLET”和它有什么不同“让”?似乎以'let'定义某个临时变量的范围的方式来定义一些临时函数的范围。 – vrume21 2013-04-11 00:53:05

+0

Rainer的答案是为了澄清其中隐含的一点:当你调用'mappend'时,你需要传递函数参数为'#'some-func'。获得符号“some-func”的函数值,然后将其作为'fn'的值传递给'mappend'。 – Mars 2013-04-11 03:58:17

6

#'是句法糖function#'foo被读作(function foo)

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

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# '富或' 富是等效的:

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) 
+0

但是,不要这样做, '#'foo'和''foo'不等于'(function foo)'和'(quote foo)'。也就是说,即使它们可以在某些相同的情况下使用,也不是很好。无论哪种方式,使用带引号的符号都会遮掩代码的含义。 – jwmc 2013-04-11 07:36:18

+3

不适用于本地功能。 '(flet((foo()'bar))(funcall'foo))'不起作用。另外,在'(funcall(function bar))'和(funcall'bar)之间使用优化编译器时可能会有细微的差别。后者可能会始终通过符号查找函数,而第一个可能会查看优化后的查找,并使用当前(编译期间)函数绑定期间的查找。文件编译器可能想要这样做。所以:使用'FUNCTION'或'#''是一致的。如果您想要全局函数的后期绑定,请使用该符号。 – 2013-04-11 08:29:02

+0

更新为'flet'使用。注意:我同意使用'#''但我的选择不是在OQ中提出的。 – GoZoner 2013-04-11 18:02:30