11

我正在学习一点关于 LISP 中的函数式编程的知识,这就是我遇到的问题:LISP 使用 CAR、CDR 函数以及 FIRST 和 REST 函数。两者都与列表有关。

从我目前所了解到的情况来看,这两者之间是有区别的,但我不太明白有什么区别。

有人可以为我总结一下吗?以及如何最终使用 CDR、CAR 实现 FIRST/REST?


编辑:由于接受的答案提到了文档,但没有链接,这里是CAR/CDR文档的链接,然后是FIRST/REST

此外 - 重要说明 - 链接的文档是 CLISP 的“只是实施说明”,这是一个常用的环境。一般来说,几乎不可能找到这种语言的“官方文件”。

4

4 回答 4

14

就它们的作用而言,carcdr相当于firstrest。这在文档中非常清楚。HyperSpec 在firstsecond和 &c 的条目上说:

第一个、第二个、第三个、第四个、第五个、第六个、第七个、第八个、第九个和第十个函数分别访问列表的第一个、第二个、第三个、第四个、第五个、第六个、第七个、第八个、第九个和第十个元素。具体来说,

(first list)    ==   (car list)
(second list)   ==   (car (cdr list))
(third list)    ==   (car (cddr list))

笔记:

第一个在功能上等同于汽车,第二个在功能上等同于 cadr,第三个在功能上等同于 caddr,第四个在功能上等同于 cadddr。

现在,当您使用这些功能时,存在差异,不是在功能上,而是在风格上。这实际上也在 HyperSpec 中被调用,例如,在rest条目中:

笔记:

当论点被主观地视为一个列表而不是一个缺点时,rest 在风格上通常比 cdr 更受欢迎。

例如,考虑两种映射从 cons 单元构建的结构的方法。首先,我们在一个 cons 单元树上进行映射,对的每个叶子(即非 cons)调用一些函数。我们用consp检查某个东西是否是 cons ,如果是,我们递归到它的carcdr上。我们通过调用cons将结果合并到一个新的 cons 单元格中。

(defun map-over-cons (function tree)
  (if (not (consp tree))
      (funcall function tree)
      (cons (map-over-cons function (car tree))
            (map-over-cons function (cdr tree)))))

或者,当我们映射一个列表时,我们通常使用endp(或null,但endp强调我们正在寻找列表的结尾,而不仅仅是寻找nil)检查终止条件,我们调用该函数列表的第一个并递归到列表的其余部分。虽然看到使用cons构造的结果很常见,但实际上list*会在使用两个参数调用时执行相同的任务(通常,它可以做更多),强调正在构造一个列表:

(defun map-over-list (function list)
  (if (endp list)
      '()
      (list* (funcall function (first list))
             (map-over-list function (rest list)))))

这些函数中的任何一个都可以使用carcdrcons编写,或者使用firstrestlist*或它们的任意组合编写,但是坚持使用其中一个可以帮助以后可能阅读代码的人(包括原始代码)作者),并表明作者的意图

以及如何最终使用 CDR、CAR 实现 FIRST/REST?

怎么样:

(defun first (x) (car x))
(defun rest (x) (cdr x))

或者甚至更好,如果你有符号功能

(setf (symbol-function 'first) (symbol-function 'car))
(setf (symbol-function 'rest) (symbol-function 'cdr))
于 2015-04-28T13:39:29.227 回答
4

您正在使用列表的操作first和信号:一系列以空列表结尾的对,即它的形式为 (list x1 ... xn)rest

您正在处理的数据结构的操作carcdr信号是用对构建的,这可能不是一个列表。

那就是选择firstrest当你使用列表时,让代码更容易被其他人阅读。

于 2015-04-28T11:38:36.457 回答
3

经典地,car 和 cdr 更面向机器,而 first 和 rest 是更抽象的函数。实际上,它们之间没有区别。每个人都坚持 car 和 cdr,所以 car 和 cdr 占了上风。

如果您很难找到 car 和 first 之间的任何区别,那是因为没有区别。首先看作为汽车的别名。

定义?

(defun first (x) (car x))
(defun rest (x) (cdr x))
于 2015-04-27T23:06:12.060 回答
2

首先,这些都不是谓词(或者至少,它们不是 Lisp 程序员所说的“谓词”;在这种情况下,“谓词”的意思是“返回布尔值的函数”)。

至于这个问题,让我们先来看看 REPL。

; SLIME 2014-12-23
CL-USER> (describe #'car)
#<FUNCTION CAR>
  [compiled function]

Lambda-list: (LIST)
Declared type: (FUNCTION (LIST) (VALUES T &OPTIONAL))
Documentation:
  Return the 1st object in a list.
Known attributes: foldable, flushable, unsafely-flushable
Source file: SYS:SRC;CODE;LIST.LISP
; No value
CL-USER> (describe #'first)
#<FUNCTION FIRST>
  [compiled function]

Lambda-list: (LIST)
Declared type: (FUNCTION (LIST) (VALUES T &OPTIONAL))
Documentation:
  Return the 1st object in a list or NIL if the list is empty.
Known attributes: foldable, flushable, unsafely-flushable
Source file: SYS:SRC;CODE;LIST.LISP
; No value
CL-USER> (describe #'cdr)
#<FUNCTION CDR>
  [compiled function]

Lambda-list: (LIST)
Declared type: (FUNCTION (LIST) (VALUES T &OPTIONAL))
Documentation:
  Return all but the first object in a list.
Known attributes: foldable, flushable, unsafely-flushable
Source file: SYS:SRC;CODE;LIST.LISP
; No value
CL-USER> (describe #'rest)
#<FUNCTION REST>
  [compiled function]

Lambda-list: (LIST)
Declared type: (FUNCTION (LIST) (VALUES T &OPTIONAL))
Documentation:
  Means the same as the cdr of a list.
Known attributes: foldable, flushable, unsafely-flushable
Source file: SYS:SRC;CODE;LIST.LISP
; No value

因此,根据文档及其签名,car等同于first并且cdr等同于rest. 让我们测试一下。

CL-USER> (cons 1 2)
(1 . 2)
CL-USER> (car (cons 1 2))
1
CL-USER> (first (cons 1 2))
1
CL-USER> (cdr (cons 1 2))
2
CL-USER> (rest (cons 1 2))
2
CL-USER> (cons 1 nil)
(1)
CL-USER> (car (cons 1 nil))
1
CL-USER> (first (cons 1 nil))
1
CL-USER> (cdr (cons 1 nil))
NIL
CL-USER> (rest (cons 1 nil))
NIL
CL-USER> nil
NIL
CL-USER> (car nil)
NIL
CL-USER> (first nil)
NIL
CL-USER> (cdr nil)
NIL
CL-USER> (rest nil)
NIL

所以,它们似乎是一样的。

于 2015-04-28T00:44:41.200 回答