В момент выполнения некоторых системных операций (функций, операторов), в которых может вызываться пользовательский код (например, при использовании sort), для этого кода запрещены побочные эффекты (действия).
Рассмотрим следующий пример:
В зависимости от особенностей реализации dolist, данный код может просто вывести
(что скорее всего и ожидается), но может также вывести и
Вот вероятная реализация dolist для первого варианта
А вот вероятная реализация dolist для второго варианта
В общем случае, деструктивная модификация структуры, которая может нарушить порядок перечисления элементов, запрещена. Частные случаи перечислены ниже.
Для операций перечисления элементов списка, cdr цепочка не может быть деструктивно модифицирована.
Для операций, которые перечисляют элементы массива, данный массив не может быть расширен (смотрите adjust-array) и, при наличии, не может быть изменен указатель заполнения.
Для операций перечисления элементов хеш-таблицы (таких как with-hash-table-iterator и maphash, в пользовательком коде не могут добавляться в данную таблицу новые элементы.
Для операций перечисления символов пакета (например, with-package-iterator и do-symbols) в пакет не могут интернироваться, дезинтернироваться новые символы, которые относятся к данному пакету. Однако текущий обрабатываемый символ может быть дезинтернирован.
Деструктивные операции, такие как delete, требуют более жёстких ограничений и эти ограничения описаны отельно в каждой функции.
Таблица 7.1 содержит большинство операций и функций запрещающих побочные эффекты в пользовательском коде, которые в них передаются в качестве тела для исполнения или в виде функционального объекта.
Кроме того, следует отметить, что пользовательский код не должен модифицировать структуру списка, которая интерпретируется вычислителем, который был вызван неявно или явно с помощью eval. Например, как в случае функции-ловушки (функция вывода defstruct, значение *evalhook* или *applyhook*, и так далее), которая является замыканием интерпретируемого кода. Также, функции вывода defstruct и другие ловушки не должны выполнять побочные действия над выводимыми структурами, или над строками переданными в make-string-input-stream. В целом, будте бдительны.
Следует отметить, что такие операции как mapcar или dolist работают не только с cdr указателями (при прохождении к концу списка), но также и с car указателями (при обработке непосредственно элемента). Ограничения побочных эффектов относятся и к одному, и ко второму указателям.
adjoin | maphash | reduce |
assoc | mapl | remove |
assoc-if | maplist | remove-duplicates |
assoc-if-not | member | remove-if |
count | member-if | remove-if-not |
count-if | member-if-not | search |
count-if-not | merge | set-difference |
delete | mismatch | set-exclusive-or |
delete-duplicates | nintersection | some |
delete-if | notany | sort |
delete-if-not | notevery | stable-sort |
do-all-symbols | nset-difference | sublis |
do-external-symbols | nset-exclusive-or | subsetp |
do-symbols | nsublis | subst |
dolist | nsubst | subst-if |
eval | nsubst-if | subst-if-not |
every | nsubst-if-not | substitute |
find | nsubstitute | substitute-if |
find-if | nsubstitute-if | substitute-if-not |
find-if-not | nsubstitute-if-not | tree-equal |
intersection | nunion | union |
некоторые loop выражения | position | with-hash-table-iterator |
map | position-if | with-input-from-string |
mapc | position-if-not | with-output-to-string |
mapcan | rassoc | with-package-iterator |
mapcar | rassoc-if | |
mapcon | rassoc-if-not |