Clojure: минусы (сек) и кон (список) - PullRequest
96 голосов
/ 09 июня 2010

Я знаю, что cons возвращает seq, а conj возвращает коллекцию. Я также знаю, что conj «добавляет» элемент в оптимальный конец коллекции, а cons всегда «добавляет» элемент вперед. Этот пример иллюстрирует обе эти точки:

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)

Для векторов, карт и наборов эти различия имеют смысл для меня. Однако для списков они кажутся идентичными.

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)

Существуют ли примеры использования списков, где conj против cons демонстрируют различное поведение или они действительно взаимозаменяемы? По-разному, есть ли пример, когда список и последовательность не могут использоваться одинаково?

Ответы [ 5 ]

146 голосов
/ 10 июня 2010

Одно отличие состоит в том, что conj принимает любое количество аргументов для вставки в коллекцию, а cons принимает только один:

(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

Другое отличие заключается в классе возвращаемого значения:

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

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

Обратите внимание, что они на самом деле не взаимозаменяемы;в частности, clojure.lang.Cons не реализует clojure.lang.Counted, поэтому count для него больше не является операцией с постоянным временем (в этом случае он, вероятно, уменьшится до 1 + 3 - 1 получается из линейного обхода за первыйЭлемент, 3 происходит от (next (cons 4 '(1 2 3)), являющегося PersistentList и, таким образом, Counted).

Намерение, стоящее за именами, заключается в том, что, как я полагаю, cons означает "против"1018 * 1 , тогда как conj означает соединение (или предмет в коллекцию).seq, создаваемый с помощью cons, начинается с элемента, переданного в качестве первого аргумента, и имеет в качестве next / rest часть вещь, полученную в результате применения seq ко второму аргументу;как показано выше, все это класса clojure.lang.Cons.Напротив, conj всегда возвращает коллекцию примерно того же типа, что и переданная ему коллекция.(Грубо говоря, поскольку PersistentArrayMap будет превращено в PersistentHashMap, как только оно превысит 9 записей.)


1 Традиционно, в мире Лисп, cons cons (транспортирует пару), поэтому Clojure отходит от традиции Lisp, поскольку ее функция cons создает последовательность, которая не имеет традиционной cdr.Обобщенное использование cons для обозначения «создания записи того или иного типа для удержания нескольких значений вместе» в настоящее время повсеместно используется при изучении языков программирования и их реализации;это то, что имеется в виду, когда упоминается "избегать употребления".

9 голосов
/ 09 июня 2010

Насколько я понимаю, то, что вы говорите, правда: выражение «con» в списке равнозначно «против» в списке.

Вы можете думать о Con как о операции «вставка куда-то», а в качестве «операции вставки в начало».В список наиболее логично вставлять заголовок, поэтому в данном случае "против" и "против" эквивалентны.

8 голосов
/ 29 августа 2010

Другое отличие состоит в том, что поскольку conj принимает последовательность в качестве первого аргумента, она прекрасно сочетается с alter при обновлении ref до некоторой последовательности:

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

Это в основном делает (conj a-sequence-ref an-item) потокобезопасным способом. Это не будет работать с cons. См. Главу о параллелизме в Программирование Clojure Стю Хэллоуэем для получения дополнительной информации.

2 голосов
/ 24 января 2014

Другое различие заключается в поведении списка?

(list? (conj () 1)) ;=> true
(list? (cons 1 ())) ; => false
0 голосов
/ 03 мая 2019

В библиотеке Тупело есть выделенные функции для добавления добавляемых или добавляемых значений в любой последовательной коллекции:

(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]
...