clojure:no cons cells

问题描述 投票:12回答:4

我听说,clojure在大多数lisp语言中都没有cons细胞

这是否意味着Clojure列表不以空列表结尾?

任何人都可以解释这到底意味着什么吗?

clojure scheme lisp common-lisp cons
4个回答
24
投票

Lisp提供了原始的cons数据结构及其表示法。

请参见John McCarthy, Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I, 1960, Chapter 3, Recursive Functions of Symbolic Expressions

该章介绍:

  • 由原子组成的符号表达式和使用点符号编写的成对符号表达式:( a . b )
  • 用于简化某些符号表达式(a b c)的列表符号
  • 终止列表的原子符号nil
  • 原始函数carcdrconseqatom
  • 其他几个功能:ffsubstequalnullcadrcaddrnullappendamongpairassocsublisapplyeval,...

早在Lisp中,已添加了用于更改cons细胞的功能:rplaca(表示replace car)和rplacd(表示replace cdr)。参见LISP 1.5 Programmer's Manual by John McCarthy et al. from 1962。这些函数使我们能够编写破坏性函数,也使我们能够创建基于循环cons的数据结构,例如循环列表。

Common Lisp

通常,Lisp方言实现了大部分功能。 Common Lisp也不例外,其功能在Common Lisp标准Conses中进行了描述。使用上述功能的示例:

; pair two lists into a list of cons cells
; the function pair is called pairlis in Common Lisp
CL-USER 17 > (pairlis '(john mary eva) `(34 29 40))
((EVA . 40) (MARY . 29) (JOHN . 34))

; find a cons cell in a list of cons cells,
; based on the content of the car of those cons cells
CL-USER 18 > (assoc 'eva
                    (pairlis '(john mary eva)
                             `(34 29 40)))
(EVA . 40)

; create a tree out of cons cells and atoms
CL-USER 19 > (cons (cons 10 20) (cons 30 40))
((10 . 20) 30 . 40)

; a cons cell is not an atom
CL-USER 20 > (atom (cons 1 2))
NIL

; a cons cell is not nil
CL-USER 21 > (null (cons 1 2))
NIL

; substitute an item with a new one in a tree
CL-USER 22 > (subst 30                          ; new
                    'bar                        ; old
                    '((10 . 20) . (bar . 40)))  ; tree
((10 . 20) 30 . 40)   ; also written as  ((10 . 20) . (30 . 40))

; substitute several items in a tree, using an assoc list
; to describe the substitutions
CL-USER 23 > (sublis '((a . 10) (d . 40))      ; substitutions
                     '((a . b) . (c . d)))     ; tree
((10 . B) C . 40)

列表是符号表达式的特例。它们通常不带点写:

CL-USER 24 > '(a . (b . nil))
(A B)

Common Lisp还支持Lisp 1.5的变异操作rplacarplacd

CL-USER 25 > (let ((c (cons 0 1)))              ; create a cons
               (print c)                        ; print it
               (print (rplaca c 'foo))          ; replace the car
               (print (rplacd c 'bar))          ; replace the cdr
               (print (eq c (rplaca c 'baz)))   ; identical ?
               (values))
(0 . 1)      ; the cons cell
(FOO . 1)    ; car replaced
(FOO . BAR)  ; cdr replaced
T            ; still the same object

Emacs Lisp

Emacs Lisp还实现了上述功能:

ELISP> (sublis '((a . 10) (d . 40))                                             
               '((a . b) . (c . d)))
((10 . b) c . 40)

Clojure

如John McCarthy所述,

Clojure不支持这些符号表达式。它没有缺点单元格,没有点符号,并且不提供上述接口。例如atom在Clojure中的含义完全不同。 cons不会创建约束单元。列表不是由cons单元组成的。

在Clojure中,点只是另一个符号:

user=> (count '(1 . 2))
3

有一个原始函数可以构造lists

user=> (list 1 2 3)
(1 2 3)

结果应为列表:

user=> (list? (list 1 2 3))
true

有一个称为cons的功能:

user=> (cons 0 (list 1 2 3))
(0 1 2 3)

以某种方式这不是列表:

user=> (list? (cons 0 (list 1 2 3)))
false

Basic Clojure确实使用不同的数据结构(-> sequences逻辑列表),并具有自己的命名和语义。即使名称与Lisp名称相似,也不要指望它们具有相同的功能。

方案

编程语言Scheme也提供类似于上面的con单元。它缺少某些功能,但可以轻松实现。例如,sublis可能在Scheme中这样实现(请参阅initdr.scm):

(define (sublis alist tree)
  (if (pair? tree)
      (cons (sublis alist (car tree))
            (sublis alist (cdr tree)))
      (if (assv tree alist)
          (cdr (assv tree alist))
          tree)))

7
投票
  • Clojure确实有一个缺点结构:clojure.lang.Cons
  • 用于cons调用的结果
  • ...,别无其他:既没有列表,也没有向量,也没有任何类型的惰性序列。
  • 一般也不能用于成对的对象:tail /rest/cdr是一个序列,而不是Object
  • [如果您将cons内容添加到列表,向量或惰性序列中,您得到Cons
  • 但是,正如其他答案明确指出的那样,没有函数可以交易Cons es。它们一般都按顺序处理。

[另一种用法:conj插入不确定的序列(既不是向量列表,也不是set或map ...)会产生Cons


6
投票

根据this page from clojure.org

consfirstrest操纵序列抽象,而不是具体的cons单元格

Clojure列表不以空列表结尾,并且它们不是传统的con单元格。它们是实现排序的数据结构。 This page on programming to abstractions解释了Clojure的“适当”结构的方法,包括列表:

通常,抽象编程使您能够使用不同数据结构上的函数库,而不管这些数据结构如何实现,从而为您提供了强大的功能。

因此Clojure列表就像cons单元格一样,它们实现了consfirstrest,但这仅意味着它们共享一个公共接口。它们的基础实现有所不同,但是它们都是“适当的”。


1
投票

在Common Lisp中,列表是con单元格的序列。每个缺点单元有两个插槽或指针,分别称为“ car”和“ cdr”。汽车指向(或持有)任何东西。 cdr通常指向另一个cons单元格或nilnil计为列表的末尾。 Clojure为其列表提供了大致相同的功能,但基础表示形式有所不同。它确实具有称为Cons的数据类型,但并非所有列表或给定列表的所有部分都是根据Cons构建的。 (现在,如果您尚未阅读jmargolisvt的答案,则应该阅读。)[编辑:其他答案表明,我在这里所说的关于Clojure中的列表和Conses之间的关系是不正确的。有人可能会觉得它在非正式的“列表”意义上是正确的,或者不是。]

还请注意,部分由于序列抽象的思想,列表本身在Clojure中的通用性远低于Common Lisp或Scheme。但是,其他类型的序列也很常见。

值得一提的是,在Clojure中,您不能假设在打印输出时看起来像列表的东西实际上就是列表。例如,它可能是一个惰性序列,被not视为列表。

以下是一些可能使用列表的Clojure示例:

user=> (def foo (list 1))
#'user/foo
user=> foo
(1)
user=> (class foo)
clojure.lang.PersistentList
user=> (def bar (cons 2 foo))
#'user/bar
user=> bar
(2 1)
user=> (class bar)
clojure.lang.Cons

(即使foo返回不同的数据类型,barclass都被视为列表。]

user=> (next bar)
(1)
user=> (rest bar)
(1)
user=> (class (next bar))
clojure.lang.PersistentList
user=> (class (rest bar))
clojure.lang.PersistentList
user=> (next foo)
nil
user=> (rest foo)
()
user=> (= nil ())
false
user=> (rest ())
()
user=> (rest nil)
()
user=> (next ())
nil
user=> (next nil)
nil

在Common Lisp中,您可以将一个对象限制到列表或nil以外的另一个对象上。结果是一个“虚线列表” (1 . 2),它是一个单个cons单元格,其中cdr指针指向的不是另一个cons单元格或nil,而是在普通列表中。让我们在Clojure中尝试一下:

user=> (cons 1 2)
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long  clojure.lang.RT.seqFrom (RT.java:528)

[虽然我在这里,但与Common Lisp相比还有一个显着差异(其中nil =()=否::

user=> (= nil false)
false
user=> (= () false)
false

但是,即使nil不是false,也可以像false一样使用它:

user=> (if nil "nil works like true" "nil works like false")
"nil works like false"

但是,您不能使用空白列表执行此操作:

user=> (if () "() works like true" "() works like false")
"() works like true"
“它自己的美。)
© www.soinside.com 2019 - 2024. All rights reserved.