Беда с макросами Lisp - PullRequest
       36

Беда с макросами Lisp

2 голосов
/ 01 июня 2011

Я пытаюсь написать макрос на Лиспе, который заново реализует let, используя себя.Это тривиальное упражнение, которое не имеет практической цели;однако после ответа на связанный вопрос я понял, что, вероятно, мне следует больше узнать о макросах.Они рекламируются как одна из замечательных вещей в Лиспе, но я редко их использую.

В любом случае, вот что я попробовал сначала:

(defmacro mylet (args &rest exp) `(let ,args (dolist (x ,exp) x)))

но когда я пытаюсь что-то вроде:

 (mylet ((a 5) (b 2)) (print (+ a b)))

это выдает ошибку:

  #1=(PRINT (+ A B)) is not a symbol or lambda expression in the form (#1#) .

аргументы (a и b) установлены правильно, но оператор print не работает.Я думаю, это потому, что я использую два уровня косвенности - ссылаясь на переменную, которую я создал в макросе.Но я не могу понять, как это исправить!Есть идеи?

1 Ответ

4 голосов
/ 01 июня 2011

Ваш макрос расширяется до:

(LET ((A 5) (B 2))
  (DOLIST (X ((PRINT (+ A B)))) X))

, что недопустимо, поскольку ((PRINT (+ A B))) не является допустимым выражением.Существует также проблема, заключающаяся в том, что использование интернированного символа в раскрытии макроса может привести к захвату переменной, но это не имеет прямого отношения (подробнее см. PCL ).

Использование DOLIST здесь не нужно,и скомпилирован для получения правильного (вам нужно было бы преобразовать все подчиненные формы в анонимную функцию, чтобы поместить их в список, выполнить их последовательную последовательность, а затем сохранить конечный результат, чтобы соответствовать поведению PROGN).Вы можете просто использовать PROGN или, поскольку LET включает в себя неявный PROGN, просто соединить тело с помощью функции @ функции обратного цитирования:

(defmacro mylet (args &body exp) `(let ,args ,(cons 'progn exp)))

(defmacro mylet (args &body exp) `(let ,args ,@exp))
...