我正在学习一点关于LISP中函数编程的知识,以下是我遇到的问题:LISP使用CAR、CDR函数以及FIRST和REST函数。两者都与列表有关。
从我目前所了解到的情况来看,这两者之间有区别,但我不太明白区别是什么
有人能为我总结一下吗?我最终如何使用CDR、CAR实现FIRST/REST?
编辑:由于接受的答案提到文档,但没有链接,这里是CAR/CDR文档的链接,然后是FIRST/REST文档的链接。
此外,重要的一点是,链接文档只是CLISP的"实施说明",CLISP是一种常用的环境。一般来说,几乎不可能找到像这样的语言的"官方文件"。
就它们的功能而言,car和cdr相当于first与rest。这在文档中非常清楚。HyperSpec在第一个、第二个&c:
函数第一、第二、第三、第四、第五、第六、第七,第八、第九和第十访问第一、第二、第三、第四、,列表的第五、第六、第七、第八、第九和第十元素,分别地具体而言,
(first list) == (car list) (second list) == (car (cdr list)) (third list) == (car (cddr list))
…
注意事项:
第一种功能等同于汽车,第二种功能等效于cadr,第三个在功能上等效于caddr,以及第四个在功能上等同于cadddr。
现在,当您使用这些函数时,有的区别,不是在功能上,而是在风格上。这实际上也在HyperSpec中调用,例如,在rest:上的条目中
注意:
当论点是被主观地看作是一个列表而不是一个缺点。
例如,考虑两种映射由cons单元构建的结构的方法。在第一个例子中,我们在cons单元格的树上进行映射,用树的每个叶(即非cons)调用一些函数。我们用consc检查某个东西是否是cons,如果是,我们递归到它的car和cdr上。我们通过调用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,但end强调我们正在寻找列表的end,而不仅仅是寻找nil)检查终端条件,并且我们调用列表的第一个上的函数,并递归到列表的其余中。虽然使用cons构建结果是很常见的,但实际上有list*在使用两个参数调用时将执行相同的任务(通常,它可以做得更多),强调正在构建列表:
(defun map-over-list (function list)
(if (endp list)
'()
(list* (funcall function (first list))
(map-over-list function (rest list)))))
这些函数中的任何一个都可以使用car、cdr和cons编写,或者使用first,rest以及list*或它们的任何组合编写,但坚持其中一个或另一个有助于以后阅读代码的人(包括原作者),并表明作者的意图。
我最终如何使用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))
操作first
和rest
表示您正在使用列表:一系列以空列表结尾的对,即其形式为(list x1…xn)
操作car
和cdr
表示您正在使用对构建数据结构,这可能不是列表。
也就是说,当您使用列表时,请选择first
和rest
,以使其他人更容易阅读代码。
传统上,car和cdr更倾向于面向机器,而first和rest则是更抽象的函数。事实上,它们之间没有区别。每个人都坚持car和cdr,所以car和cd占了上风。
若你们很难找到汽车和第一辆之间的区别,那个是因为并没有区别。首先将其视为汽车的别名。
定义?
(defun first (x) (car x))
(defun rest (x) (cdr x))
首先,这些都不是谓词(或者至少,它们不是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
所以,它们似乎是一样的。