행동

2014-11-21 3 views
3
FUZZ> (defvar *foo* nil) 
*FOO* 
FUZZ> (defmacro bar() 
     (format t "foo: ~A" *foo*) 
     `(+ 1 1)) 
BAR 
FUZZ> (defmacro bot() 
     (let ((*foo* 17)) 
      `(bar))) 
BOT 
FUZZ> (bot) 
foo: NIL 

내 정신 모델 (명확하게 잘못은) 다음과 같은 순서대로 일이 말한다 *foo* (17)의 현재 값을 인쇄하고 매크로가 아닌 (+ 1 1) 양식을 반환하는 매크로 확장 bar의 매크로 확장 시간이 끝났으며 이제는 (+ 1 1) 양식을 평가하고 2을 반환합니다.행동

왜 내가 잘못 되었습니까?

내가 원하는 것을 쉽게 할 수 있습니까?

+1

, 그래서 내 실수가'의 결합을 생각했다 * foo는 *'역학적 변수처럼, 모든 ** 시간 동안 효과 ** 차례대로 모든 양식을 매크로 확장 (핵심) 및 (결정적으로) 가져 갔다. 사실, 일단'(bar)'가 반환되면, Joshua가 분명히하는 것처럼 우리는'* foo *'로 끝난다. – gtod

답변

5

REPL에 (bot)을 평가하라는 메시지가 표시되면 먼저 매크로 확장을 수행해야합니다. 그것은 (bar)를 반환하고 let이 풀리는에서 결합

(let ((*foo* 17)) 
    `(bar)) 

평가 사실상 수단 macroexpansion bot 함수를 호출한다. 이제 (bar)이 있습니다. bar 매크로이므로이 foo: NIL를 출력하고 (+ 1 1)를 반환

(progn 
    (format t "foo: ~a" *foo*) 
    `(+ 1 1)) 

을 평가 수단 macroexpansion의 또 다른 라운드를위한 시간이다.

매크로 확장을 일부 바인딩 범위에서 수행하려면 macroexpansion 함수를 직접 호출해야합니다. 예를 들어, 당신이 macroexpand을 사용할 수 있습니다 : 당신이 자신을 macroexpansion 할 거라면,

CL-USER> (defparameter *foo* nil) 
*FOO* 
CL-USER> (defmacro bar() 
      (format t "foo: ~a" *foo*) 
      `(+ 1 1)) 
BAR 
CL-USER> (defmacro baz() 
      (let ((*foo* 42)) 
      (macroexpand '(bar)))) 
BAZ 
CL-USER> (baz) 
foo: 42 
2 

을하지만, environment arguments을 유지해야합니다. 이 경우, baz의 더 나은 정의는 다음과 같습니다 아

(defmacro baz (&environment env) 
    (let ((*foo* 42)) 
    (macroexpand '(bar) env)))