107 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | ||
| title: Clojure Lists They Are Everything
 | ||
| localeTitle: 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") 
 | ||
| ```
 | ||
| 
 | ||
|  [IDEOne!](https://ideone.com/6c7UxY)
 | ||
| 
 | ||
| ## Добавление в список
 | ||
| 
 | ||
| Списки предназначены для добавления, а не для добавления. Нет никакого реального способа добавления в список. Вы можете перейти к списку с помощью `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) 
 | ||
| ```
 | ||
| 
 | ||
| Этот пример немного продвинут, и вы не должны его понимать, если вы новичок. Это просто пример того, что вы можете сделать с ленивыми последовательностями. Возможно, вы все равно это поймете!
 | ||
| 
 | ||
|  [IDEOne!](https://ideone.com/jwpvt8)
 | ||
| 
 | ||
| ## Когда использовать список?
 | ||
| 
 | ||
| Использование вектора обычно предпочтительнее использования списка, так как нет никакого риска, что компилятор случайно оценивает вектор как функцию, и быстрее получить доступ к произвольным элементам вектора. Списки наиболее полезны в трех случаях:
 | ||
| 
 | ||
| *   Создание кода с использованием макроса.
 | ||
| *   Создание «бесконечных» ленивых последовательностей.
 | ||
| *   Предоставление элементов коллекции.
 | ||
| 
 | ||
| | [ Предыдущая](//forum.freecodecamp.com/t/clojure-collections/18411) | [ Главная ](//forum.freecodecamp.com/t/clojure-resources/18422) | [следующий ](//forum.freecodecamp.com/t/clojure-vectors/18421) |  
 | ||
| | [Коллекции](//forum.freecodecamp.com/t/clojure-collections/18411) | [Содержание](//forum.freecodecamp.com/t/clojure-resources/18422) | [Векторы](//forum.freecodecamp.com/t/clojure-vectors/18421) | |