Многие функции строят списки, поскольку списки лежат в самой основе Lisp.
cons — это фундаментальная функция построения списков; однако
интересно отметить, что в исходном коде Emacs list используется
чаще, чем cons.
Эта функция является самой базовой для создания новой структуры списка. Она создаёт новую ячейку cons, помещая object1 в CAR, а object2 в CDR. Затем она возвращает новую ячейку cons. Аргументы object1 и object2 могут быть любыми объектами Lisp, но чаще всего object2 является списком.
(cons 1 '(2))
⇒ (1 2)
(cons 1 '())
⇒ (1)
(cons 1 2)
⇒ (1 . 2)
cons часто используется для добавления одного элемента в начало
списка. Это называется consing элемента в список.
6
Например:
(setq list (cons newelt list))
Обратите внимание, что нет конфликта между переменной с именем list,
используемой в этом примере, и функцией с именем list, описанной ниже;
любой символ может служить обеим целям.
Эта функция создаёт список, элементами которого являются objects.
Результирующий список всегда завершается nil. Если objects
не заданы, возвращается пустой список.
(list 1 2 3 4 5)
⇒ (1 2 3 4 5)
(list 1 2 '(3 4 5) 'foo)
⇒ (1 2 (3 4 5) foo)
(list)
⇒ nil
Эта функция создаёт список из length элементов, каждый из
которых равен object. Сравните make-list с
make-string (см. Создание строк).
(make-list 3 'pigs)
⇒ (pigs pigs pigs)
(make-list 0 'pigs)
⇒ nil
(setq l (make-list 3 '(a b)))
⇒ ((a b) (a b) (a b))
(eq (car l) (cadr l))
⇒ t
Эта функция возвращает список, содержащий все элементы
sequences. Аргументы sequences могут быть списками, векторами,
bool-векторами или строками, но последний обычно должен быть списком.
Все аргументы, кроме последнего, копируются, поэтому ни один из аргументов
не изменяется. (См. nconc в Функции перестановки списков для способа
объединения списков без копирования.)
В более общем случае, последний аргумент append может быть любым
объектом Lisp. Последний аргумент не копируется и не преобразуется; он
становится CDR последней ячейки cons в новом списке. Если последний
аргумент сам является списком, то его элементы фактически становятся
элементами результирующего списка. Если последний элемент не является
списком, результатом является точечный список, поскольку его последний
CDR не равен nil, как требуется в правильном списке
(см. Списки и ячейки cons).
Вот пример использования append:
(setq trees '(pine oak))
⇒ (pine oak)
(setq more-trees (append '(maple birch) trees))
⇒ (maple birch pine oak)
trees
⇒ (pine oak)
more-trees
⇒ (maple birch pine oak)
(eq trees (cdr (cdr more-trees)))
⇒ t
Вы можете увидеть, как работает append, взглянув на диаграмму в виде
блоков. Переменная trees устанавливается в список (pine oak),
а затем переменная more-trees устанавливается в список (maple
birch pine oak). Однако переменная trees продолжает ссылаться на
исходный список:
more-trees trees
| |
| --- --- --- --- -> --- --- --- ---
--> | | |--> | | |--> | | |--> | | |--> nil
--- --- --- --- --- --- --- ---
| | | |
| | | |
--> maple -->birch --> pine --> oak
Пустая последовательность не вносит вклада в значение, возвращаемое
append. Как следствие, последний аргумент nil приводит к
копированию предыдущего аргумента:
trees
⇒ (pine oak)
(setq wood (append trees nil))
⇒ (pine oak)
wood
⇒ (pine oak)
(eq wood trees)
⇒ nil
Когда-то это был обычный способ копирования списка до того, как была
изобретена функция copy-sequence. См. Последовательности, массивы и векторы.
Здесь мы показываем использование векторов и строк в качестве аргументов
append:
(append [a b] "cd" nil)
⇒ (a b 99 100)
Вот как преобразовать строку в список её символов:
(append "abcd" nil)
⇒ (97 98 99 100)
Функция string-to-list является удобным сокращением для
вышеуказанного.
С помощью apply (см. Вызов функций) мы можем объединить
все списки из списка списков:
(apply 'append '((a b c) nil (x y z) nil))
⇒ (a b c x y z)
Если sequences не заданы, возвращается nil:
(append)
⇒ nil
Вот несколько примеров, где последний аргумент не является списком:
(append '(x y) 'z)
⇒ (x y . z)
(append '(x y) [z])
⇒ (x y . [z])
Второй пример показывает, что когда последний аргумент является последовательностью, но не списком, элементы этой последовательности не становятся элементами результирующего списка. Вместо этого последовательность становится последним CDR, как и любой другой последний аргумент, не являющийся списком.
В виде исключения, если все аргументы, кроме последнего, равны nil,
а последний аргумент не является списком, возвращаемое значение равно этому
последнему аргументу без изменений (т.е. в этом случае возвращаемое
значение не является списком):
(append nil nil "abcd")
⇒ "abcd"
Эта функция возвращает копию дерева tree. Если tree является ячейкой cons, она создаёт новую ячейку cons с теми же CAR и CDR, а затем рекурсивно копирует CAR и CDR таким же образом.
Обычно, когда tree не является ячейкой cons,
copy-tree просто возвращает tree. Однако, если
vectors-and-records не равен nil, он также копирует векторы и
записи (и рекурсивно обрабатывает их элементы). Аргумент tree не
должен содержать циклов.
Эта функция возвращает «сплющенную» копию tree, то есть
список, содержащий все ненулевые (nil) терминальные узлы, или листья,
дерева ячеек cons, корнем которого является tree. Листья в
возвращаемом списке находятся в том же порядке, что и в tree.
(flatten-tree '(1 (2 . 3) nil (4 5 (6)) 7))
⇒(1 2 3 4 5 6 7)
Эта функция возвращает object в виде списка. Если object уже является списком, функция возвращает его; в противном случае функция возвращает список из одного элемента, содержащий object.
Это обычно полезно, если у вас есть переменная, которая может быть или не быть списком, и вы можете затем сказать, например:
(dolist (elem (ensure-list foo)) (princ elem))
Эта функция возвращает список чисел, начинающийся с from и
увеличивающийся на separation, и заканчивающийся на или перед
to. separation может быть положительным или отрицательным и по
умолчанию равен 1. Если to равен nil или численно равен
from, значением является список из одного элемента
(from). Если to меньше from при положительном
separation или больше from при отрицательном separation,
значением является nil, поскольку эти аргументы задают пустую
последовательность.
Если separation равен 0, а to не равен nil и не
численно равен from, number-sequence сигнализирует об
ошибке, поскольку эти аргументы задают бесконечную последовательность.
Все аргументы являются числами.
Аргументы с плавающей запятой могут быть сложными, потому что
арифметика с плавающей запятой неточна. Например, в зависимости от машины
вполне может случиться, что (number-sequence 0.4 0.6 0.2) вернёт
список из одного элемента (0.4), тогда как
(number-sequence 0.4 0.8 0.2) вернёт список из трёх
элементов. n-й элемент списка вычисляется по точной
формуле (+ from (* n separation)). Таким образом,
если нужно гарантировать, что to включён в список, можно
передать для to выражение именно такого точного типа. Альтернативно,
можно заменить to на чуть большее значение (или чуть более
отрицательное, если separation отрицателен).
Некоторые примеры:
(number-sequence 4 9)
⇒ (4 5 6 7 8 9)
(number-sequence 9 4 -1)
⇒ (9 8 7 6 5 4)
(number-sequence 9 4 -2)
⇒ (9 7 5)
(number-sequence 8)
⇒ (8)
(number-sequence 8 5)
⇒ nil
(number-sequence 5 8 -1)
⇒ nil
(number-sequence 1.5 6 2)
⇒ (1.5 3.5 5.5)
Не существует строго эквивалентного способа добавить элемент в
конец списка. Можно использовать (append listname (list
newelt)), который создаёт совершенно новый список, копируя
listname и добавляя newelt в его конец. Или можно
использовать (nconc listname (list newelt)), который
изменяет listname, проходя по всем CDR и затем заменяя
завершающий nil. Сравните это с добавлением элемента в начало
списка с помощью cons, который ни копирует, ни изменяет список.