Мой первый макрос на Лиспе; это дырявый?

Я работал с Practical Common Lisp и в качестве упражнения решил написать макрос, чтобы определить, является ли число кратное другому числу:

(defmacro multp (value factor)
`(= (rem ,value ,factor) 0))

так что: (multp 40 10) оценивается как true, а (multp 40 13) нет

Вопрос в том, не пропускает ли этот макрос в каким-то образом? И это "хороший" Лисп? Есть ли уже существующая функция/макрос, которую я мог бы использовать?


person Tom Martin    schedule 13.09.2008    source источник


Ответы (4)


Siebel дает обширный список (по крайней мере, для простых случаев) возможных источников утечек, и здесь их нет. И value, и factor оцениваются только один раз и по порядку, а rem не имеет побочных эффектов.

Однако это не очень хороший Лисп, потому что в этом случае нет причин использовать макрос. Функция

(defun multp (value factor)
  (zerop (rem value factor)))

идентичен для всех практических целей. (Обратите внимание на использование zerop. Я думаю, что в данном случае это проясняет ситуацию, но в тех случаях, когда вам нужно выделить, что тестируемое значение все еще может иметь смысл, если оно отличается от нуля, (= ... 0) может быть лучше)

person Community    schedule 13.09.2008
comment
Спасибо большое. Есть какие-нибудь идеи о требованиях к простому оправданному макросу для создания в качестве упражнения? - person Tom Martin; 13.09.2008

Ваш макрос меня устраивает. Я не знаю, что такое дырявый макрос, но ваш довольно прост и не требует никаких gensyms. Если это «хороший» Лисп, мое эмпирическое правило состоит в том, чтобы использовать макрос только тогда, когда функция не подходит, и в этом случае функцию можно использовать вместо вашего макроса. Однако, если это решение работает для вас, нет причин не использовать его.

person Kyle Cronin    schedule 13.09.2008

Ну, в принципе, пользователь мог бы сделать так:

(flet ((= (&rest args) nil))
  (multp 40 10))

который оценивается как NIL... за исключением того, что ANSI CL делает незаконным повторное связывание большинства стандартных символов, включая CL:=, так что в этом конкретном случае вы в безопасности.

В целом, конечно, вы должны знать как о ссылочной непрозрачности (захват идентификаторов из контекста, в котором раскрывается макрос), так и о негигиеничности макросов (утечка идентификаторов в расширенный код).

person Matthias Benkard    schedule 17.09.2008

Нет, ни один символ, введенный в «лексическое замыкание» макроса, не высвобождается наружу.

Обратите внимание, что утечка НЕ ​​ОБЯЗАТЕЛЬНО плохая вещь, даже если случайная утечка почти всегда такова. Для одного проекта, над которым я работал, я обнаружил, что макрос, подобный этому, был полезен:

(defmacro ana-and (&rest forms)
  (loop for form in (reverse forms)
        for completion = form then `(let ((it ,form))
                                      (when it
                                       ,completion))
        finally (return completion)))

Это позволило мне получить «короткое замыкание» вещей, которые нужно было сделать последовательно, с аргументами, перенесенными из предыдущих вызовов в последовательности (и отказ сигнализировался возвратом NIL). Конкретный контекст, из которого взят этот код, предназначен для написанного от руки синтаксического анализатора файла конфигурации, который имеет достаточно сложный синтаксис, поэтому написание правильного синтаксического анализатора с использованием генератора синтаксических анализаторов было более трудоемким, чем ручная работа.

person Vatine    schedule 06.11.2008