(Правовая оговорка - я знаю о значении Seqs в Clojure),
В языке Common LISP функция недостатков может использоваться для объединения двух символов в список:
(def s 'x)
(def l 'y)
(cons s l)
В clojure - Вы можете только недостатки на последовательность - недостатки не были расширены для работы с двумя символами. Таким образом, необходимо записать:
(def s 'x)
(def l 'y)
(cons s '(l))
Существует ли высокоуровневый шаблон в Clojure, который объясняет это различие между языком Common LISP и Clojure?
В Clojure, в отличие от традиционных Лиспов, списки не являются первичными структурами данных. Структуры данных могут реализовывать интерфейс ISeq , который представляет собой другое представление данной структуры данных, позволяя одним и тем же функциям обращаться к элементам в каждом из них. (В списках это уже реализовано. seq?
проверяет, реализует ли что-то ISeq . (seq? '(1 2)), (seq? [1 2]))
Clojure просто действует по-другому (по уважительной причине) в том смысле, что при использовании cons
последовательность (на самом деле она имеет тип clojure.lang.Cons
), построенная из a
и (seq b)
возвращается. ( a
является аргументом 1 и b
аргументом 2) Очевидно, символы не могут и не могут реализовать ISeq .
Скринкаст / выступление Рича Хики Тем не менее, обратите внимание, что rest
изменился, и его предыдущее поведение теперь находится в следующем
, и что lazy-cons
был заменен на lazy-seq
и cons
.
В Common Lisp CONS создает так называемую ячейку CONS, которая похожа на запись с двумя слотами: 'car' и ' cdr '.
В эти два слота cons-ячейки можно поместить ЧТО-нибудь.
Ячейки Cons используются для построения списков. Но можно создавать все виды структур данных с cons-ячейками: деревья, графы, различные типы специализированных списков, ...
Реализации Lisp сильно оптимизированы для обеспечения очень эффективных cons-ячеек.
Список Лиспа - это просто обычный способ использования cons-ячеек (см. описание Райнера ). Clojure лучше всего воспринимается как не имеющий cons-ячеек (хотя что-то подобное может скрываться под капотом). Clojure cons
- неправильное название, на самом деле его следует называть просто prepend
.
В Clojure предпочтительно использовать двухэлементный вектор: [:a :b]
. Под капотом такие маленькие векторы реализуются как массивы Java и являются чрезвычайно простыми и быстрыми.
Короткой рукой для (cons :a '(:b))
(или (cons :a (cons :b nil))
) является list
: (list :a :b)
.
Когда вы говорите
> (cons 'a 'b)
в common lisp, вы получаете не список, а точечную пару: (a . b)
, тогда как результатом
> (cons 'a (cons 'b nil))
будет точечная пара (a . ( b . nil))
.
В первом списке cdr()
не является списком, так как здесь b
, а не nil
, что делает его неправильным списком. Правильные списки должны завершаться nil
. Поэтому функции более высокого порядка, такие как mapcar()
и другие, не будут работать, но мы экономим cons-ячейку. Я полагаю, что разработчики Clojure убрали эту возможность из-за путаницы, которую она могла вызвать.