Почему компиляция макроса Common Lisp в моей среде дает результат, отличный от результата книги? Можно ли добиться того же самого?

#macros #common-lisp #lisp-macros

Вопрос:

Я пытаюсь изучить общий шепелявый язык с помощью книги Общий шепелявый язык: мягкое введение в символические вычисления. Кроме того, я использую SBCL, Emacs и Slime.

В главе 14, последней, автор рассматривает макросы. В одном из разделов о его составлении он упоминает:

Поскольку расширение макросов может произойти в любое время, вам не следует писать макросы, которые вызывают побочные эффекты, такие как назначения или ввод-вывод. Но это нормально, если макрос расширяется до выражения, которое вызывает побочные эффекты.

Чтобы проиллюстрировать плохие макросы, он приводит следующий пример:

 (defmacro bad-announce-macro ()
 (format t "~%Hi mom!"))


(defun say-hi ()
 (bad-announce-macro))

> (compile ’say-hi)
Hi, mom!
SAY-HI

> (say-hi)
NIL
 

Когда я пытаюсь воспроизвести то же самое в своей среде, у меня получается другой результат:

 
CL-USER> (defmacro bad-announce-macro ()
            (format t "~%Hi mom!"))
BAD-ANNOUNCE-MACRO
CL-USER> (bad-announce-macro)
Hi mom!
NIL
CL-USER> (defun say-hi ()
           (bad-announce-macro))
Hi mom!
SAY-HI
CL-USER> (say-hi)
NIL
CL-USER> (compile (say-hi))
; Evaluation aborted on #<UNDEFINED-FUNCTION NIL {100408C143}>.
CL-USER> (compile 'say-hi)
SAY-HI
NIL
NIL
CL-USER> (compile `say-hi)
SAY-HI
NIL
NIL

 

Как вы видите, при компиляции функции Hi mom! часть отсутствует.

Почему это происходит? Это только из-за различий в реализациях Lisp? Возможно ли достичь того же результата?

Я не думаю, что это так, но я помещу распечатку из книги, на случай, если это связано с копированием из pdf и вставкой в РЕПЛ Emacs Slime.

введите описание изображения здесь

Ответ №1:

SBCL по умолчанию уже компилирует определения в REPL. вызов compile уже скомпилированной функции, вероятно, ничего не даст.

Hi, mom! Сообщение уже распечатано, когда defun форма будет выполнена. См.Ваш пример выше.

Турецкий использовал для своей книги другую реализацию, в которой использовался переводчик в REPL. Компилятор будет затем вызван пользователем с помощью вызова compile compile-file , или аналогично.