8.2 KiB
title | localeTitle |
---|---|
Clojure Lists They Are Everything | Clojure Списки Они все |
Списки являются фундаментальными для Clojure. Clojure - это Lisp, а Lisps были первоначально использованы для обработки списка. Все в Лиспе - это список!
(def foo "bar")
Этот кусок кода на самом деле является списком! Так что все между двумя круглыми скобками в Clojure. Интересно, не так ли? Это то, что делает Lisps настолько интересным - вы можете легко написать код, который генерирует новый код, потому что генерировать код так же просто, как составить список.
Создание фактического списка
Проблема в том, что, поскольку все это список в Clojure, что-то вроде этого вернет ошибку:
(1 2 3 4 5)
; => ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn
Какое ужасное сообщение об ошибке. Что REPL пытается сказать нам, это: «1 не является функцией, и ее нельзя превратить в одну». Поскольку все в Lisp является списком, первый элемент любого списка рассматривается как функция, например def
, +
или str
, поэтому, если мы пишем (1 2 3 4 5)
, он обрабатывает первый элемент ( 1
) как функции, которой это явно не является.
Мы можем решить это двумя способами. Один использует функцию list
для построения списка, например, используя str
для объединения строк вместе.
(list 1 2 3 4 5)
; => (1 2 3 4 5)
Вы также можете использовать цитирование. Цитирование списка в основном говорит компилятору, что этот список не является вызовом функции, и он не должен оценивать какой-либо из кода внутри него.
'(1 2 3 4 5)
; => (1 2 3 4 5)
Интересно, что вы также можете вызывать вызовы функций. Вот как работают макросы. Они довольно сложны и заслуживают собственной статьи, поэтому мы не будем здесь останавливаться.
;; Without a ' to quote it, this would return "foobarbaz".
'(str "foo" "bar" "baz")
; => (str "foo" "bar" "baz")
Добавление в список
Списки предназначены для добавления, а не для добавления. Нет никакого реального способа добавления в список. Вы можете перейти к списку с помощью cons
. conj
также работает, но это предназначено для векторов, а cons
быстрее для списков.
(cons 1 '(2 3 4))
; => (1 2 3 4)
Извлечение из списков
Вы извлекаете элементы из списков с помощью nth
. get
не работает в списках, поскольку списки предназначены для последовательного доступа, а не для произвольного доступа. Обратите внимание, что nth
работает с векторами, но медленнее, чем get
из-за этого.
(nth '(1 2 3 4) 0)
; => 1
Преобразование других коллекций в списки
Функция list
не может преобразовать другие коллекции в списки, потому что она пытается построить список с использованием аргументов, которые ему даны. При пересылке list
коллекция вернет список, содержащий эту коллекцию.
(list [1 2 3 4 5])
; => ([1 2 3 4 5])
Для преобразования в список используйте функцию seq
.
(seq [1 2 3 4 5])
; => (1 2 3 4 5)
Ленивые последовательности
Clojure имеет блестящую функцию, называемую «ленивые последовательности». Ленивая последовательность - это список, элементы которого не сгенерированы, пока вы не обратитесь к элементу последовательности позже, и в этот момент он оценивает все элементы последовательности до тех пор, пока вы не захотите. Это позволяет создавать «бесконечные» последовательности!
range
- это, пожалуй, самая простая ленивая последовательность. Он содержит все числа.
(range 10)
; => (0 1 2 3 4 5 6 7 8 9)
(range -5 5)
; => (-5 -4 -3 -2 -1 0 1 2 3 4)
Вы можете использовать ленивые последовательности, чтобы делать действительно классные вещи, например, генерировать ленивую последовательность всех чисел фибоначчи.
(def fibs
(lazy-cat [0 1] (map + (rest fibs) fibs)))
(take 10 fibs) ;; this means, "evaluate the first 10 fibonacci numbers."
; => (0 1 1 2 3 5 8 13 21 34)
Этот пример немного продвинут, и вы не должны его понимать, если вы новичок. Это просто пример того, что вы можете сделать с ленивыми последовательностями. Возможно, вы все равно это поймете!
Когда использовать список?
Использование вектора обычно предпочтительнее использования списка, так как нет никакого риска, что компилятор случайно оценивает вектор как функцию, и быстрее получить доступ к произвольным элементам вектора. Списки наиболее полезны в трех случаях:
- Создание кода с использованием макроса.
- Создание «бесконечных» ленивых последовательностей.
- Предоставление элементов коллекции.
| Предыдущая | Главная | следующий |
| Коллекции | Содержание | Векторы |