freeCodeCamp/guide/russian/clojure/lists-are-everything/index.md

8.2 KiB
Raw Blame History

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") 

:rocket: IDEOne!

Добавление в список

Списки предназначены для добавления, а не для добавления. Нет никакого реального способа добавления в список. Вы можете перейти к списку с помощью 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) 

Этот пример немного продвинут, и вы не должны его понимать, если вы новичок. Это просто пример того, что вы можете сделать с ленивыми последовательностями. Возможно, вы все равно это поймете!

:rocket: IDEOne!

Когда использовать список?

Использование вектора обычно предпочтительнее использования списка, так как нет никакого риска, что компилятор случайно оценивает вектор как функцию, и быстрее получить доступ к произвольным элементам вектора. Списки наиболее полезны в трех случаях:

  • Создание кода с использованием макроса.
  • Создание «бесконечных» ленивых последовательностей.
  • Предоставление элементов коллекции.

| :point_left: Предыдущая | :book: Главная :book: | следующий :point_right: |
| Коллекции | Содержание | Векторы |