Clojure: eksileri (seq) ve conj (liste)


100

Bunun consbir seq conjdöndürdüğünü ve bir koleksiyon döndürdüğünü biliyorum . Ayrıca conj, öğeyi koleksiyonun optimum sonuna cons"eklediğini" ve öğeyi her zaman öne "eklediğini" de biliyorum . Bu örnek, bu noktaların her ikisini de göstermektedir:

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)

Vektörler, haritalar ve kümeler için bu farklılıklar bana mantıklı geliyor. Ancak listeler için aynı görünüyorlar.

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)

Farklı davranışlar sergileyen conjve conssergileyen listeleri kullanan herhangi bir örnek var mı yoksa bunlar gerçekten değiştirilebilir mi? Farklı bir şekilde ifade edilirse, bir liste ve bir sekansın eşit olarak kullanılamayacağı bir örnek var mı?

Yanıtlar:


153

Bir fark, conjbir koleksiyona eklemek için herhangi bir sayıda argümanı kabul ederken cons, yalnızca bir tane alır:

(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

Diğer bir fark, dönüş değerinin sınıfındadır:

(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList

(class (cons 4 '(1 2 3))
; => clojure.lang.Cons

Bunların gerçekten birbirinin yerine kullanılamayacağını unutmayın; özellikle, clojure.lang.Consuygulanmaz clojure.lang.Counted, bu nedenle bir countüzerinde artık sabit zamanlı bir işlem değildir (bu durumda muhtemelen 1 + 3'e düşecektir - 1, ilk elemanın doğrusal geçişinden gelir, 3 (next (cons 4 '(1 2 3)), a olmaktan gelir PersistentListve böylece Counted).

İsimlerin ardındaki amaç bunu olduğunu düşünüyoruz conseksileri için araçlar (bir seq truct) 1 oysa conj(bir koleksiyon üzerine bir öğe oin) vasıtası conj için. seqİnşa edilen consilk bağımsız değişken olarak kabul elemanı ile başlar ve onun kadar olan next/ restparçasının uygulanması ile elde edilen şey seq, ikinci değişken için; yukarıda gösterildiği gibi, her şey sınıftır clojure.lang.Cons. Bunun tersine, conjher zaman kabaca kendisine geçirilen koleksiyonla aynı türde bir koleksiyon döndürür. (Kabaca, çünkü a PersistentArrayMap, PersistentHashMap9 girişi aştığı anda a'ya dönüşecektir .)


1 Geleneksel olarak, Lisp dünyasında, consters düşmektedir (bir çifti çıkarır), bu nedenle Clojure, Lisp geleneğinden, consişlevinin geleneksel olmayan bir sekans oluşturmasını sağlamakla ayrılır cdr. cons"Bir dizi değeri bir arada tutmak için bir tür veya başka türde bir kayıt oluşturmak" anlamının genelleştirilmiş kullanımı şu anda programlama dilleri ve bunların uygulanmasında her yerde bulunur; "Düşünmekten kaçınmaktan" bahsedildiğinde kastedilen budur.


1
Ne harika bir yazı! Eksileri olduğunun farkında değildim. Aferin!
Daniel Yankowsky

Teşekkürler. Bunu duyduğuma memnun oldum. :-)
Michał Marczyk

2
Bu arada, özel bir durum olarak, (cons foo nil)bir tekli döndürür PersistentList(ve aynı şekilde için conj).
Michał Marczyk

1
Başka bir mükemmel açıklama. Sen gerçekten bir clojure jedi'sın!
dbyrne

1
Deneyimlerime göre, performans önemli olduğunda listeleri sırayla değil, listeler olarak ele almak önemlidir.
cgrand

11

Anladığım kadarıyla söylediğiniz doğru: bir listedeki birleşik bir listedeki eksilere eşdeğerdir.

Bağlanmayı bir "bir yere yerleştirme" işlemi olarak düşünebilirsiniz ve eksilerini "kafaya yerleştirme" işlemi olarak düşünebilirsiniz. Bir listede, başa eklemek en mantıklı olanıdır, bu nedenle bu durumda bağ ve eksiler eşdeğerdir.


8

Diğer bir fark ise, conjbir diziyi ilk argüman olarak aldığı için alter, a'yı bir refdiziye güncellerken güzelce oynamasıdır:

(dosync (alter a-sequence-ref conj an-item))

Bu, temelde (conj a-sequence-ref an-item)iş parçacığı açısından güvenli bir şekilde yapar. Bu işe yaramaz cons. Daha fazla bilgi için Stu Halloway tarafından Programlama Clojure'da Eş Zamanlılık bölümüne bakın .


2

Diğer bir fark listenin davranışı mı?

(list? (conj () 1)) ;=> true
(list? (cons 1 ())) ; => false

4
Eksileri her zaman sağlanan dizinin aynısını döndüren bir dizi döndürür
Ning Sun

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.