Clojure: cons(seq) vs. conj(list)
我知道
1 2 3 4 | user=> (conj [1 2 3] 4) //returns a collection [1 2 3 4] user=> (cons 4 [1 2 3]) //returns a seq (4 1 2 3) |
对于矢量,地图和集合,这些差异对我来说很有意义。 但是,对于列表,它们似乎相同。
1 2 3 4 | user=> (conj (list 3 2 1) 4) //returns a list (4 3 2 1) user=> (cons 4 (list 3 2 1)) //returns a seq (4 3 2 1) |
是否存在使用
一个区别是
1 2 3 4 5 | (conj '(1 2 3) 4 5 6) ; => (6 5 4 1 2 3) (cons 4 5 6 '(1 2 3)) ; => IllegalArgumentException due to wrong arity |
另一个区别在于返回值的类别:
1 2 3 4 5 | (class (conj '(1 2 3) 4)) ; => clojure.lang.PersistentList (class (cons 4 '(1 2 3)) ; => clojure.lang.Cons |
注意,这些并不是真正可以互换的。特别是
我相信名称的意图是
1传统上,在Lisp世界中,
我的理解是您所说的是正确的:列表上的conj等同于列表上的cons。
您可以将conj看作是"在某处插入"操作,而将cons看作是"在头插入"操作。在列表上,最合逻辑的是插入到头部,因此conj和cons在这种情况下是等效的。
另一个区别是,由于
1 | (dosync (alter a-sequence-ref conj an-item)) |
这基本上以线程安全的方式执行
列表的另一个区别是行为?
1 2 | (list? (conj () 1)) ;=> true (list? (cons 1 ())) ; => false |
Tupelo库中有专用的功能,可以向任何顺序集合添加附加值或前置值:
1 2 3 4 5 | (append [1 2] 3 ) ;=> [1 2 3 ] (append [1 2] 3 4) ;=> [1 2 3 4] (prepend 3 [2 1]) ;=> [ 3 2 1] (prepend 4 3 [2 1]) ;=> [4 3 2 1] |