Nikodemus Siivola - Nikodemus' Common Lisp FAQ
Название: | Nikodemus' Common Lisp FAQ | |
Автор: | Nikodemus Siivola | |
Жанр: | Самиздат, сетевая литература, Литература ХXI века (эпоха Глобализации экономики), Любительские переводы, Lisp, Scheme | |
Изадано в серии: | неизвестно | |
Издательство: | Интернет-издательство «Stribog» | |
Год издания: | 2021 | |
ISBN: | неизвестно | |
Отзывы: | Комментировать | |
Рейтинг: | ||
Поделись книгой с друзьями! Помощь сайту: донат на оплату сервера |
Краткое содержание книги "Nikodemus' Common Lisp FAQ"
Последнее обновление: 2012-04-13.
Это очень неофициальное ЧаВО по языку Common Lisp, отражающее субъективное мнение Nikodemus Siivola. Этот текст частично основан на других ЧаВО, встречавшихся на просторах интернета и comp.lang.lisp.
Если вы думаете, что я воспользовался вашим текстом, буду рад признаться в этом, поэтому пишите на nikodemus@random-state.net.
Текущая версия этого ЧаВО доступна по следующим адресам:
http://random-state.net/files/nikodemus-cl-faq.txt
http://random-state.net/files/nikodemus-cl-faq.html
ЧаВО также периодически публикуется в comp.lang.lisp.
Читаем онлайн "Nikodemus' Common Lisp FAQ". [Страница - 4]
(apply function elt args))
list))
Незачем писать MAP-LIST-WITH-1 с помощью APPLY, вызов FUNCALL почти наверняка будет более эффективным.
В противовес MAP-LIST-WITH-N не может быть написан с использованием FUNCALL, поскольку количество аргументов вызывающей стороне неизвестно. Следует использовать APPLY.
SET, SETQ и SETF — в чем разница, что использовать?
Короткий ответ: всегда используйте SETF.
Развернутый ответ: Давным давно, когда еще не было Common Lisp, не было лексических переменных, были только динамические. И не было тогда ни SETQ, ни SETF, только SET. То, что сегодня пишется как
(setf (symbol-value '*foo*) 42)
записывалось так
(set (quote *foo*) 42)
что со временем сократилось до SETQ (SET Quoted)
(setq *foo* 42)
Потом появились лексические переменные и SETQ стали использовать и для их присваивания, так что SETQ перестал быть просто оберткой вокруг SET.
Позже кто-то изобрел SETF (SET Field) как обобщенный способ присвоения значений в структурах данных, зеркальное отображение L-значений в других языках:
x.car:= 42;
записывается как
(setf (car x) 42)
Для симметрии и общности, SETF также включает в себя функциональность SETQ. Можно сказать, что SETQ был низкоуровневым примитивом, а SETF — высокоуровневой операцией.
Потом появились символьные макросы. Поскольку символьные макросы прозрачны, было сделано так, что SETQ ведет себя как SETF в случае, когда присваиваемая «переменная» на деле символьный макрос:
(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))
foo => 42
(setq foo 13)
foo => 13
*hidden* => (13. 42)
И вот мы попадаем в наши дни: SET и SETQ по сути атавизм, оставшийся от старых диалектов и, возможно, будет выкинут из того, что будет следующим Common Lisp'ом.
Всегда пользуйтесь SETF.
'(1 2 3) или (list 1 2 3)?
Короткий ответ: пишите(list 1 2 3)
пока не поймете разницу. Если вы пишете
'(1 2 3)
не модифицируйте это деструктивно (т. е. с помощью SORT или NREVERSE).
Развернутый ответ: Во-первых, одинарная кавычка — это макрос, преобразующий
'anything
в
(quote anything)
во время чтения, так что
'(1 2 3) === (quote (1 2 3))
Во-вторых, QUOTE — это специальный оператор, возвращающий свои аргументы невычисленными. Так
'(1 2 3)
возвращает буквальный (literal) список. Как и в большинстве языков модификация буквальных (literal) данных приводит к неопределенным последствиям. Например, компилятор может соединить константы, содержащие литералы:
(let ((a '(1 2 3))
(b '(1 2 3)))
(eq a b)) ; => T или NIL
Следствием является тот факт, что изменяя A, также может измениться и B. Тогда для чего годится QUOTE?
Если, например, у вас есть большие неизменяемые списки, которые компилятор может соединить, то пометка их как буквальные (literal) дает компилятору право так поступить.
Что за *УШКИ*?
Что бы вы ни использовали для объявления переменных, DEFVAR или DEFPARAMETER, всегда делайте *ТАКОЕ-ИМЯ*. И не делайте так для локальных переменных.(defvar *очень-хорошо*…)
(defvar это-очень-плохо…)
Зачем? Если вы еще не знаете, что такое специальные переменные, продолжайте читать ту книжку, которую читаете и возвращайтесь как закончите, а пока используйте ушки.
Ушки защищают от двух простых ошибок, которые очень легко сделать.
Ошибка 1: случайное связывание специальной переменной
(defparameter foo "foo!")
(defun say-it ()
(write-line foo))
(defun say-more (foo)
(say-it)
(format t "now say ~A~%" foo))
Теперь
(say-more "bar!")
напечатает
say bar!
now say bar!
вместо ожидаемого
say foo!
now say bar!
… упс!
Ошибка 2: из-за опечатки производится чтение из специальной вместо локальной переменной, предупреждения не выдается
Обычно вы получите предупреждение времени компиляции и ошибку времени выполнения в случае(defun foo (bar)
bat)
но если перед этим написать
(defparameter bat "baseball")
то ошибки не будет и вы потратите уйму времени на отладку, пытаясь понять, что не так.
Если пишете код для себя, все равно, ставите вы ушки или нет, но когда вы публикуете код, отсутствие *ушек* означает трату времени других людей. Не делайте так, пожалуйста!
Отсутствие ушек создает ощущение ошибки: когда я вижу
(defparameter нет-ушек…)
я понимаю, что нужно читать код особенно осторожно, потому как нет никакой гарантии, что код, который с первого --">