我正在学习LISP中的函数式编程,这是我遇到的问题:LISP使用CAR,CDR函数以及FIRST和REST函数。两者都与列表有关。
从我到目前为止所学到的,这两者之间存在差异,但我不太清楚它们之间的区别。
有人可以为我总结一下吗?我如何最终使用CDR,CAR实现FIRST / REST?
修改:由于已接受的答案提及文档但未链接,因此以下是CAR/CDR文档的链接,此处为FIRST/REST。
此外 - 重要提示 - 链接文档是CLISP的“实施说明”,这是一种常用的环境。一般来说,几乎不可能找到这种语言的“官方文件”。
答案 0 :(得分:11)
就他们的行为而言,汽车和 cdr 相当于第一次和休息。这在文档中非常清楚。 HyperSpec在 first , second ,& c:
的条目中说明第一,第二,第三,第四,第五,第六,第七, 第八,第九和第十进入第一,第二,第三,第四, 列表的第五,第六,第七,第八,第九和第十个元素, 分别。具体地,
(first list) == (car list) (second list) == (car (cdr list)) (third list) == (car (cddr list))
...
注意:
首先在功能上等同于汽车,第二是在功能上 相当于cadr,第三是功能上相当于caddr,和 第四是在功能上等同于cadddr。
现在,当您使用这些功能时, 是一个区别,而不是功能,而是 style 。这实际上也是在HyperSpec中调用的,例如,在rest上的条目中<:p>
注意:
当参数为时,休息通常优先于cdr 被主观地视为一个列表而不是一个缺点。
例如,考虑两种映射在由cons单元构建的结构上的方法。在第一个中,我们在cons单元的树上进行映射,用树的每个叶子(即,非缺点)调用一些函数。我们检查某些内容是否与 consp 有关,如果是,我们会递归到 car 和 cdr 。我们通过调用缺点将结果合并到一个新的利弊单元中。
(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 >强调的终端条件我们正在寻找列表的 end ,而不只是寻找 nil ),我们在列表的第一个并递归到列表的 rest 。虽然看到使用缺点构建的结果很常见,但实际上list*在使用两个参数调用时会执行相同的任务(通常,它可以做多一点)强调正在构建列表:
(defun map-over-list (function list)
(if (endp list)
'()
(list* (funcall function (first list))
(map-over-list function (rest list)))))
这些功能中的任何一个都可以使用 car , cdr 和缺点或第一个来编写, 休息,列表* ,或者它们的任意组合,但坚持一个或另一个可以帮助那些可能稍后阅读代码的人(包括原作者),并发出作者意图的信号。
我如何最终使用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))
答案 1 :(得分:3)
操作first
和rest
表示您正在使用列表:一系列以空列表结尾的对,即它的形式(列表x1 ... xn)
操作car
和cdr
表示您正在使用成对构建数据结构,这可能不是列表。
当您使用列表时,请选择first
和rest
,以便让其他人更轻松地阅读代码。
答案 2 :(得分:2)
经典,汽车和cdr更多的是机器导向,而第一次和休息是更抽象的功能。实际上,它们之间没有区别。每个人都坚持汽车和司机,所以汽车和司机都占了上风。
如果你很难找到汽车和汽车之间的任何差异,那就是因为没有。首先看一下汽车的别名。
解释
visible_when = 'age >= 18 or last_name!="Smith"',
答案 3 :(得分:2)
首先,这些都不是谓词(或者至少,它们不是Lisp程序员所称的&#34;谓词&#34 ;;在这种情况下,&#34;谓词&#34;表示&#34; 34;一个返回布尔值的函数&#34;)。
关于这个问题,让我们快速进入一个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
所以,他们似乎是一样的。