为什么conj和cons的参数顺序不同?

4
conj 函数中,原始集合是 第一个参数,在 cons 函数中,它是 第二个参数
我是 clojure 的新手,这似乎有点令人困惑。这两个函数具有类似的行为,但为什么参数顺序不同,这是有意设计的吗?
(conj '(1 2 3) 4)
; => (4 1 2 3)

(cons 4 '(1 2 3))
; => (4 1 2 3)

我知道这两个函数是不同的,但为什么conjcons将原始集合放置在不同的参数顺序中。
3个回答

5

cons 传统上指将第一个参数添加到第二个参数之前构造新对象,这就是参数的顺序。

以下是来自 LISP cons 的引用:

在 LISP 术语中,“将 x 添加到 y” 表示通过 (cons x y) 构造一个新对象

但是 conjoin 通常是在给定数据结构上附加的操作,具体取决于你使用的 clojure 数据类型。这就是为什么集合首先出现,然后是要附加的元素。

让我们看看 Vector

user=> (type [3 5 7 11])
clojure.lang.PersistentVector

user=> (cons 1 [3 5 7 11])
(1 3 5 7 11)

user=> (conj [3 5 7 11] 13)
[3 5 7 11 13]

但对于Listconjoin也会在前面添加元素,

user=> (type '(3 5 7 11))
clojure.lang.PersistentList

user=> (cons 1 '(3 5 7 11))
(1 3 5 7 11)

user=> (conj '(3 5 7 11) 13)
(13 3 5 7 11)

conj的文档也有相关说明。

user=> (doc conj)
-------------------------
clojure.core/conj
([coll x] [coll x & xs])
  conj[oin]. Returns a new collection with the xs
    'added'. (conj nil item) returns (item).  The 'addition' may
    happen at different 'places' depending on the concrete type.
nil

该命令适用于我所知道的任何其他函数式语言。以下是在Scala中的示例:
scala> 1 +: Seq(1, 3, 5)
res1: Seq[Int] = List(1, 1, 3, 5)

scala> Seq(1, 3, 5) :+ 7
res2: Seq[Int] = List(1, 3, 5, 7)

注意:conj 很像一个操作,即数据类型需要支持它。另一方面,cons 并不操作 seq,它可以接受任何可序列化的东西。也就是说,您可以执行 (cons 1 "abc")(cons 1 (into-array [1 2])) - ClojureMostly

1
另一个答案提供了很好的概述。我也想指出由conjcons产生的类型:
(cons 1 [2 3])          => <#clojure.lang.Cons (1 2 3)>
(conj [2 3] 9)          => <#clojure.lang.PersistentVector [2 3 9]>

(cons 1 (quote (2 3)))  => <#clojure.lang.Cons (1 2 3)>
(conj (quote (2 3)) 9)  => <#clojure.lang.PersistentList (9 2 3)>

clojure.lang.Cons类型是一种顺序类型,类似于(但不完全相同于)clojure.lang.PersistentList

(supers clojure.lang.Cons) => 
  #{ clojure.lang.ASeq 
     clojure.lang.IHashEq 
     clojure.lang.IMeta 
     clojure.lang.IObj 
     clojure.lang.IPersistentCollection 
     clojure.lang.ISeq 
     clojure.lang.Obj 
     clojure.lang.Seqable 
     clojure.lang.Sequential 
     java.io.Serializable 
     java.lang.Iterable
     java.lang.Object 
     java.util.Collection 
     java.util.List }

为了简化向序列开头或结尾添加元素的过程,您可能会对appendprepend函数感兴趣。

-1
简而言之,因为它们是相反的。在 cons 中,目标元素是第一个元素,集合成为结果序列的其余部分。在 conj 中,目标元素成为最终集合的尾部。
我建议您阅读 SICP 的第一章,其中对 cons 和 consing 术语进行了很好的描述。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接