Clojure (concat[x]y)和(cons[x]y)有什么区别?

Clojure (concat[x]y)和(cons[x]y)有什么区别?,clojure,Clojure,我被困在from 4Clojure站点,在那里你需要建立一个梯形数字的惰性序列 我的第一个镜头是: (defn pascal [x] (cons x (lazy-seq (pascal (map + (cons 0 x) (conj x 0) ))))) 这不起作用: user=> (take 5 (pascal [1 1])) ([1 1] (1 2 1) (0 2 4 2) (0 0 4 8 4)

我被困在from 4Clojure站点,在那里你需要建立一个梯形数字的惰性序列

我的第一个镜头是:

(defn pascal [x]
  (cons x
   (lazy-seq
    (pascal 
     (map +
        (cons 0 x)
        (conj x 0)      
      )))))
这不起作用:

user=> (take 5 (pascal [1 1]))
([1 1] (1 2 1) (0 2 4 2) (0 0 4 8 4) (0 0 0 8 16 8))
然而,用这种方式写作是可行的:

(defn pascal2 [x]
  (cons x
   (lazy-seq
    (pascal2
     (map +
        (concat [0] x)
        (concat x [0])      
      )))))

user=> (take 5 (pascal2 [1 1]))
([1 1] (1 2 1) (1 3 3 1) (1 4 6 4 1) (1 5 10 10 5 1))
那么,我到底做错了什么?cons/conj和concat有什么区别?

根据

康杰 结合。返回带有xs“added”的新集合。(无) 项目)返回(项目)。“添加”可能发生在不同的“位置” 取决于混凝土类型

conj
接受第一个参数作为集合,这意味着
coll
必须是集合类型
conj
将返回一个新集合,其中
x
添加到
coll
中,添加
x
的位置取决于
coll
的类型

e、 g

海螺 返回一个惰性seq,表示中元素的串联 供应的colls

concat
接受所有参数作为集合类型,这与
conj
不同
concat
返回参数的串联

e、 g

欺骗 返回一个新的seq,其中x是第一个元素,seq是其余元素

cons
文件明确说明了
cons
的工作原理。
cons
的第二个参数必须是
seq

e、 g


列表上的
conj
将元素添加到列表的前面。 如果将列表转换为向量,它将起作用

user=> (conj '(1 2 3) 4)
(4 1 2 3)
user=> (conj [1 2 3] 4)
[1 2 3 4]

如其他人所述,
conj
根据具体的集合类型将其接收的元素插入不同的位置,有关
conj
cons
之间差异的更多详细信息,请参见SO问题

在第一个版本的
pascal
函数中,您提供了一个向量作为初始参数,因此表达式
(conj x 0)
将在向量末尾插入
0
,用于计算序列中的第二个元素,但是因为map返回一个惰性序列,当计算第三个元素时,插入发生在开头(
(conj(map inc'(0))2);=(21)
),这将导致从那时起序列中出现错误的元素

为了使用
cons
conj
方法,您必须确保使用
mapv
而不是
map
返回向量

(defn pascal [x]
  (cons x
   (lazy-seq
    (pascal 
     (mapv +
        (cons 0 x)
        (conj x 0))))))

(take 5 (pascal [1 1]))

;= ([1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1] [1 5 10 10 5 1])
mapv
的缺点是它很急切,因此它将计算pascal元素中的所有成员,而不是在您实际需要它们之前将其保留

另一方面,当使用
concat
时,您可以确保在末尾追加元素,并且所有内容都是惰性的,但是追加不像向量那样便宜,有关更多信息,请参阅

不管这些因素如何,您仍然可以在这两种情况下使用
cons
,因为它所做的是您在这两种情况下所需要的(即在集合的开头插入一个元素)


谢谢你的回答,现在很清楚为什么结果是错误的。现在我只需要找到康杰行为的原因…这教会我更仔细地阅读文档。谢谢谢谢,非常中肯。你知道这是为什么吗?编辑:啊,在这里:
concat clojure.core
(concat)
(concat x)
(concat x y)
(concat x y & zs)
> (concat [0] [1])
(0 1)
> (concat [0] [[1]])
(0 [1])
> (concat [0] 1) ;See the second argument is not a collection type, thus the function throws an exception.
java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long
>  
cons clojure.core 
(cons x seq)
> (cons [1] [0])
([1] 0) ; [1] is the first element and (0) is the rest
> (first (cons [1] [0]))
[1]
> (rest (cons [1] [0]))
(0)
> (cons 1 [0]) ; 1 is the first element and (0) is the rest
(1 0)
> (cons [1] 0) ;the second argument is not a seq, throwing exception
java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long
user=> (conj '(1 2 3) 4)
(4 1 2 3)
user=> (conj [1 2 3] 4)
[1 2 3 4]
(defn pascal [x]
  (cons x
   (lazy-seq
    (pascal 
     (mapv +
        (cons 0 x)
        (conj x 0))))))

(take 5 (pascal [1 1]))

;= ([1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1] [1 5 10 10 5 1])
(defn pascal2 [x]
  (cons x
   (lazy-seq
    (pascal2
     (map +
        (cons 0 x) ; Replaced concat with cons
        (concat x [0]))))))

(take 5 (pascal2 [1 1]))

;= ([1 1] (1 2 1) (1 3 3 1) (1 4 6 4 1) (1 5 10 10 5 1))