Clojure (concat[x]y)和(cons[x]y)有什么区别?
我被困在from 4Clojure站点,在那里你需要建立一个梯形数字的惰性序列 我的第一个镜头是: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)
(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))