Мой первый макрос на Лиспе; это протекает? - PullRequest
5 голосов
/ 13 сентября 2008

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

(defmacro multp (value factor)<br> `(= (rem ,value ,factor) 0))

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

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

Ответы [ 4 ]

11 голосов
/ 13 сентября 2008

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

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

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

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

2 голосов
/ 13 сентября 2008

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

1 голос
/ 17 сентября 2008

Ну, в принципе, пользователь может сделать это:

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

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

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

0 голосов
/ 06 ноября 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). Конкретный контекст, из которого взят этот код, предназначен для написанного от руки синтаксического анализатора для файла конфигурации, который имеет синтаксис, достаточно скомпонованный достаточно, чтобы написание правильного синтаксического анализатора с использованием генератора синтаксического анализатора было более трудоемким, чем откат вручную.

...