Макрос вызова функции работает в интерпретаторе, не работает в компиляторе (SBCL + CMUCL) - PullRequest
2 голосов
/ 15 ноября 2011

Как было предложено в вопросе, связанном с макросами, который я недавно отправил в SO , я закодировал макрос, называемый «быстрый», посредством вызова функции (вот отдельный код в pastebin) * * 1005

(defun main ()
  (progn
    (format t "~A~%" (+ 1 2 (* 3 4) (+ 5 (- 8 6))))
    (format t "~A~%" (fast (+ 1 2 (* 3 4) (+ 5 (- 8 6)))))))

Это работает в REPL под SBCL и CMUCL:

$ sbcl
This is SBCL 1.0.52, an implementation of ANSI Common Lisp.
...
* (load "bug.cl")
22
22

$

К сожалению, однако, код больше не компилируется:

$ sbcl
This is SBCL 1.0.52, an implementation of ANSI Common Lisp.
...
* (compile-file "bug.cl")
...
;   during macroexpansion of (FAST (+ 1 2 ...)). Use *BREAK-ON-SIGNALS* to
;   intercept:
;
;    The function COMMON-LISP-USER::CLONE is undefined.

Так что, похоже, что мои макро-функции «быстрого» вызова («клон», «операция-p») во время компиляции я вызываю проблемы в компиляторах Lisp (проверено как в CMUCL, так и в SBCL).

Есть идеи о том, что я делаю неправильно и / или как это исправить?

Ответы [ 3 ]

4 голосов
/ 17 ноября 2011

Несколько замечаний по поводу вашего кода.

  • множественные тесты объекта на равенство можно заменить на MEMBER

  • обратная цитата со следующей запятой ничего не делает. Вы можете просто удалить это.

  • вы можете убедиться, что ваши функции доступны для макроса, а) переместив эти функции в дополнительный файл и скомпилировав / загрузив их перед использованием макроса, б) используя EVAL-WHEN, чтобы сообщить компилятору оценить определение функций или c) добавить функции в макрос как локальные функции

Пример:

(defmacro fast (&rest sexpr)
  (labels ((operation-p (x)
             (member x '(+ - * /)))
           (clone (sexpr)
             (if (consp sexpr)
                 (destructuring-bind (head . tail) sexpr
                   (if (operation-p head)
                       `(the fixnum (,head ,@(clone tail)))
                     (cons (clone head) (clone tail))))
               sexpr)))
    (car (clone sexpr))))

Обратите внимание, что эта и ваша версия FAST не являются полными обходчиками кода. Они распознают только простые вызовы функций (а не другие конструкции Lisp, такие как LAMBDA, LET, FLET, LABELS и т. Д.).

2 голосов
/ 15 ноября 2011

Неважно, я понял: мне пришлось переместить функции, вызываемые макросом (и, следовательно, необходимые во время компиляции), в отдельный файл, сначала «compile-file», «загрузить» его, затем «compile-»файл "тот, что с макросом.

1 голос
/ 17 ноября 2011

Связывание с макро-расширением происходит (обычно) во время компиляции.

Это означает, что любые функции, используемые во время раскрытия макроса (обратите внимание, не обязательно в раскрытии макроса, возвращаемое значение как бы) должны быть определены, когда макрос встречается во время компиляции. *

...