2013-05-16 3 views
11

Я хотел бы изучить внутренности Lisp, поэтому я хочу посмотреть, как все реализовано.Полностью разверните макрокоманду

Например,

(macroexpand '(loop for i upto 10 collect i)) 

дает мне (в SBCL)

(BLOCK NIL 
    (LET ((I 0)) 
    (DECLARE (TYPE (AND NUMBER REAL) I)) 
    (SB-LOOP::WITH-LOOP-LIST-COLLECTION-HEAD (#:LOOP-LIST-HEAD-1026 
               #:LOOP-LIST-TAIL-1027) 
     (SB-LOOP::LOOP-BODY NIL 
          (NIL NIL (WHEN (> I '10) (GO SB-LOOP::END-LOOP)) NIL) 
          ((SB-LOOP::LOOP-COLLECT-RPLACD 
          (#:LOOP-LIST-HEAD-1026 #:LOOP-LIST-TAIL-1027) 
          (LIST I))) 
          (NIL (SB-LOOP::LOOP-REALLY-DESETQ I (1+ I)) 
          (WHEN (> I '10) (GO SB-LOOP::END-LOOP)) NIL) 
          ((RETURN-FROM NIL 
          (SB-LOOP::LOOP-COLLECT-ANSWER 
           #:LOOP-LIST-HEAD-1026))))))) 

Но LOOP ТЕЛА, С-LOOP-LIST-COLLECTION-HEAD, и т.д. все еще макросы. Как я могу полностью расширить форму макроса?

ответ

13

Чтобы увидеть полное расширение, нужно пройти форму Лиспа на всех уровнях и развернуть их. Для этого необходимо, чтобы этот так называемый хостер понимал синтаксис Lisp (а не только синтаксис s-выражения). Например, в (lambda (a b) (setf a b)) список (a b) является списком параметров и не должен быть расширен макрос.

Различные стандартные реализации Lisp предоставляют такой инструмент. Ответ 6502 упоминает MACROEXPAND-ALL, который предоставляется SBCL.

Если вы используете среду разработки, то, как правило, предоставляется в качестве команды:

  • SLIME: Mx шламовых MACROEXPAND-все с Cc Mm

  • LispWorks: меню Выражение>Прогулка или Mx Прогулка Форма, короче M-Sh -m.

+0

Когда переносимость вызывает беспокойство, попробуйте использовать макроэксперт Джона Фремлина, он работает вне SBCL и делает то же самое (хотя определения макрокоманды, по-видимому, заменены на прогностические как ненужные). –

3

Вы можете использовать MACROEXPAND-ALL, но то, что вы можете получить, не обязательно полезно.

В чем-то вроде LOOP настоящее мясо - это сам макрос, а не сгенерированный код.

1

(Примечание: Если вы не заинтересованы в переносимости, SBCL обеспечивает macroexpand-all, который будет делать то, что вы после этого Если вы после портативного решения, читайте дальше ...).

Быстрый и-грязное решение было бы macroexpand самой формой, а затем рекурсивно macroexpand все, кроме первого элемента результирующего списка. Это несовершенное решение; он будет полностью сбой в момент, когда он попытается обработать привязки let (первый аргумент let, список привязок, не предназначен для макрорасширения, но этот код все равно сделает это).

Более полное решение будет рассматривать специальные формы специально, а не макрорасширение их неоценимых аргументов. При желании я мог бы обновить такое решение.

8

Другие ответы отлично подходят для вас, но вы говорите, что хотите увидеть, как все реализовано.

Многие макросы (как вы уже знаете) реализованы с использованием макросов, а macroexpand-all очень полезен, но вы можете потерять контекст того, какой макрос несет ответственность за какие изменения.

Один хороший средний грунт (если вы используете слизь) должен использовать slime-expand-1 (C-c Enter), который показывает расширение - это еще один буфер. Затем вы можете использовать slime-expand-1 внутри этого нового буфера, чтобы развернуть макросы на месте. Это позволяет вам ходить по дереву, когда вы читаете, а также использовать отмену, чтобы снова закрыть расширения.

Для меня это было послание бога, понимающее чужие макросы. Надеюсь, это тебе тоже поможет, повеселиться!

+1

Это отличный способ. Slimv также имеет этот рабочий процесс, просто fyi для пользователей vim + lisp –

Смежные вопросы