简体   繁体   English

CDR,CAR和REST,FIRST和可能的实施之间的区别?

[英]Difference between CDR, CAR and REST, FIRST and possible implementation?

I'm learning a little bit about functional programming in LISP and here's what I've bumped into: LISP uses CAR, CDR functions as well as FIRST and REST functions. 我正在学习LISP中的函数式编程,这是我遇到的问题:LISP使用CAR,CDR函数以及FIRST和REST函数。 Both related to lists. 两者都与列表有关。

From what I've learned so far, there's a difference between these two, but I don't quite see what the difference is. 从我到目前为止所学到的,这两者之间存在差异,但我不太清楚它们之间的区别。

Could anyone sum this up for me? 有人可以为我总结一下吗? And how do I eventually implement FIRST/REST using CDR, CAR? 我如何最终使用CDR,CAR实现FIRST / REST?


Edit : Since accepted answer mentions documentation, but does not link, here is the link for the documentation for CAR/CDR , here then for FIRST/REST . 编辑 :由于接受的答案提到文档,但没有链接,这里是CAR / CDR文档的链接,这里是FIRST / REST

In addition - important note - that linked documentation is "just implementation notes" for CLISP, which is a commonly used environment. 此外 - 重要的说明 - 链接文档是CLISP的“实施说明”,这是一种常用的环境。 Generally it is almost impossible to find "official documentations" for languages such is this one. 一般来说,几乎不可能找到这种语言的“官方文件”。

In terms of what they do, car and cdr are equivalent to first and rest . 就他们所做的而言, 汽车cdr相当于第一次休息 This is quite clear in the documentation. 这在文档中非常清楚。 The HyperSpec says on the entry for first , second , &c: HyperSpec在第一个第二个和c的条目上说:

The functions first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, and tenth access the first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, and tenth elements of list, respectively. 第一,第二,第三,第四,第五,第六,第七,第八,第九和第十函数分别访问列表的第一,第二,第三,第四,第五,第六,第七,第八,第九和第十元素。 Specifically, 特别,

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

...

Notes: 笔记:

first is functionally equivalent to car, second is functionally equivalent to cadr, third is functionally equivalent to caddr, and fourth is functionally equivalent to cadddr. 第一个在功能上等同于汽车,第二个在功能上等同于cadr,第三个在功能上等同于caddr,第四个在功能上等同于cadddr。

Now, there is a difference, not in functionality, but in style , when you're using these functions. 现在, 有区别的,而不是功能,而是在风格 ,当你使用这些功能。 This is actually called out in the HyperSpec as well, eg, in the entry on rest : 这实际上也是在HyperSpec中调用的,例如,在休息条目中:

Notes: 笔记:

rest is often preferred stylistically over cdr when the argument is to being subjectively viewed as a list rather than as a cons. 当论证被主观地视为列表而不是缺点时,休息通常优先于风格而不是cdr。

For instance, consider two ways of mapping over structures built from cons cells. 例如,考虑两种映射在由cons单元构建的结构上的方法。 In the first, we're mapping over a tree of cons cells, calling some function with each leaf (ie, non-cons) of the tree. 在第一个中,我们映射在cons细胞树上 ,用的每个叶子(即,非缺点)调用一些函数。 We check whether something is a cons with consp , and if it is, we recurse onto its car and cdr . 我们检查是否有东西是consp的缺点,如果是,我们将它们递归到它的汽车cdr上 We combine the results into a new cons cell by calling cons . 我们通过调用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)))))

Alternatively, when we map over a list, we typically check for the terminal condition with endp (or null , but endp emphasizes that we're looking for the end of a list , not just looking for nil ), and we call the function on the first of the list and recurse into the rest of the list. 或者,当我们映射列表时,我们通常使用endp检查终端条件(或null ,但是endp强调我们正在寻找列表结尾 ,而不只是查找nil ),并且我们调用函数列表的第一个并递归到列表的其余部分 While it's pretty common to see the result constructed using cons , there's actually list* that will perform the same task when called with two arguments (in general, it can do a bit more) that emphasizes that a list is being constructed: 虽然看到使用cons构造的结果是很常见的,但实际上list *将在使用两个参数调用时执行相同的任务(通常,它可以执行更多操作),强调正在构造列表

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

Either of these functions could be written using car , cdr , and cons , or with first , rest , and list* , or any combination of them, but sticking to one or the other helps people that may read the code later (including the original author), and signals the intent of the author. 这些函数中的任何一个都可以使用carcdrcons ,或者firstrestlist * ,或者它们的任意组合来编写,但是坚持使用其中一个可以帮助那些可能会在以后读取代码的人(包括原始函数)作者),并表明作者的意图

And how do I eventually implement FIRST/REST using CDR, CAR? 我如何最终使用CDR,CAR实现FIRST / REST?

How about: 怎么样:

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

or possibly even better, if you have symbol-function : 或者甚至更好,如果你有符号功能

(setf (symbol-function 'first) (symbol-function 'car))
(setf (symbol-function 'rest) (symbol-function 'cdr))

The operations first and rest signals that you are working with a list: a series of pairs ending with the empty list ie it is of the form (list x1 ... xn) 操作firstrest表示您正在使用列表:一系列以空列表结尾的对,即它的形式(列表x1 ... xn)

The operations car and cdr signals that you are working on a data structure build with pairs, that potentially isn't a list. 操作carcdr表示您正在使用对构建数据结构,这可能不是列表。

That is choose first and rest when you work with lists, to make the code easier for others to read. 这是first选择并在使用列表时rest ,以便让其他人更容易阅读代码。

Classically, car and cdr have been more machine oriented while first and rest have been more abstract functions. 传统上,汽车和cdr更多的是面向机器,而第一次和休息是更抽象的功能。 In reality, there is no difference between them. 实际上,它们之间没有区别。 Everyone stuck to car and cdr, so car and cdr prevailed. 每个人都坚持汽车和司机,所以汽车和司机占了上风。

If you're having a hard time to finding any differences between car and first, it's because there is none. 如果你很难找到汽车和汽车之间的任何差异,那是因为没有。 Look at first as an alias for car. 首先看一下汽车的别名。

Definitions? 定义?

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

Firstly, none of these is a predicate (or at least, they aren't what Lisp programmers call "predicates"; in this context, "predicate" means "a function that returns a boolean value"). 首先,这些都不是谓词(或者至少,它们不是Lisp程序员所谓的“谓词”;在这种情况下,“谓词”意味着“一个返回布尔值的函数”)。

As to the question, lets hop into a REPL for a minute. 至于问题,让我们跳转到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

So, according to the documentation, and their signatures, car is equivalent to first and cdr is equivalent to rest . 因此,根据文档和他们的签名, car相当于firstcdr相当于rest Lets test this. 让我们测试一下。

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

So, they seem to be the same. 所以,他们似乎是一样的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM