2014-02-18 2 views
6

나는 같은 이름의 컴파일러 매크로를 생성하는 매크로를 작성하려고 시도 해왔다.레터 바운드 변수에 랩핑 된 매크로 폼을 생성하는 매크로

(definline foobar (a b) (print "foobar") (+ a b)) 
;; Expands to 
(define-compiler-macro foobar (a b) 
    `(let ((a ,a) (b ,b)) 
    (print "foobar") (+ a b))) 

하지만이하자 바인딩 ((a ,a) (b ,b))을 생성하는 방법을 알아낼 수 없습니다 :

(defmacro definline (name lambda-list &body body) 
    `(define-compiler-macro ,name ,lambda-list 
    `(let ,,(mapcar (lambda (v) ``(,',v ,,v)) lambda-list) 
     ,,@body))) 

내가 원하는 것은이 같은 것입니다 : 이것은 내가 함께 붙어있어 최소한의 코드입니다. 필자가 머리를 감쌀 수 없었던 문제는 람다 바인딩의 내용이 인데 컴파일시 매크로 폼을 생성하지 않고을 확장 한 것입니다. 수동으로하는 방법을 이해하지만 임의의 람다 목록에 대해 일반적으로이를 수행하는 방법을 잘 모르겠습니다.

편집 : 나는이 함께했다

좀 더 손보는 후. 어떤 작품. 그러나, 음, 그것은 끔찍합니다.

답변

3

일부 I/O 관련 변수가 수정 된 경우 format을 사용한 접근 방식은 전혀 작동하지 않습니다. 심볼 이름을 생성하기 위해 format을 사용하는 것은 일반적으로 꽤 부서지기 쉽고 이식성이 없습니다. 이 으로 해결하기가 까다로울뿐 아니라 역 인용 부호 대신 목록 구성으로 접근하는 것이 더 쉬울 수도 있습니다. 예를 들어,이 경우 우리는 할 수 :

(defmacro definline (name variables &body body) 
    (list 'define-compiler-macro name variables 
     `(list* 'let (list ,@(mapcar (lambda (variable) 
             `(list (quote ,variable) ,variable)) 
           variables)) 
       ',body))) 

이 작동되도록 :

CL-USER> (pprint (macroexpand-1 '(definline foobar (a b) 
         (print "foobar") 
         (+ a b)))) 

(DEFINE-COMPILER-MACRO FOOBAR 
    (A B) 
    (LIST* 'LET (LIST (LIST 'A A) (LIST 'B B)) '((PRINT "foobar") (+ A B)))) 

내가 뭔가를 잘못 읽고있어 않는 한, 같은 결과로해야하는 :

(define-compiler-macro foobar (a b) 
    `(let ((a ,a) (b ,b)) 
    (print "foobar") 
    (+ a b))) 

backquotes 만 사용하여 후자의 양식을 생성하는 것이 반드시 가능하다고 생각하지 않습니다. 문제는 사양이 역 인용 부호가 구현되는 방법을 정확하게 정의하지 않기 때문에 구현 다음은 확장을 쓸 수있는 방법으로 그것을 구현 않는 경우가

(define-compiler-macro foobar (a b) 
    (backquote (let ((a (unquote a)) 
        (b (unquote b))) 
       (print "foobar") 
       (+ a b))) 

같은만큼 간단하지 것입니다 그 유형의 출력을 생성합니다. 구현에서 그러한 보증을 얻지 못한다면 상위 계층에 주입해야하는 "쉼표 변수"를 얻을 수있는 방법이 없다고 생각합니다. 그것은 분명이 점을 만들기 위해 열심히하지만이 시도 볼 수 있습니다

같은 결과를 생성합니다
(defmacro definline (name variables &body body) 
    `(define-compiler-macro ,name ,variables 
    `(let ,',(mapcar (lambda (variable) 
         `(,variable (unquote ,variable))) 
         variables) 
     ,@',body))) 

: SBCL이 정상으로 역 인용 부호를 대체하기 위해 이미 충분히 스마트 것을

(DEFINE-COMPILER-MACRO FOOBAR 
    (A B) 
    '(LET ((A (UNQUOTE A)) (B (UNQUOTE B))) 
    (PRINT "foobar") 
    (+ A B))) 

공지 사항 따옴표로 묶지 않아야합니다. mapcar은 쉼표가 구현 된 방법이 지정되어 있지 않기 때문에 쉼표가있는 코드를 생성 할 수 없으며 2.4.7 Comma에 따르면 "쉼표는 역 인용 부호 표현".나는 그것이 당신의 최선의 선택 같은 것을 것을 의미한다고 생각 :

(defmacro definline (name variables &body body) 
    `(define-compiler-macro ,name ,variables 
    `(let ,(mapcar 'list 
        ',variables 
        (list ,@variables)) 
     ,@',body))) 

이것의 확장은 다른 구현에 따라 다를 것입니다 만, SBCL에 그것의 :

는 CCL에
(DEFINE-COMPILER-MACRO FOOBAR (A B) 
    `(LET (SB-IMPL::BACKQ-COMMA (MAPCAR 'LIST '(A B) (LIST A B))) 
    (PRINT "foobar") 
    (+ A B))) 

당신이 얻을 :

CLISP에서
(DEFINE-COMPILER-MACRO FOOBAR (A B) 
    (LIST* 'LET 
     (LIST* (MAPCAR 'LIST '(A B) (LIST A B)) 
       '((PRINT "foobar") (+ A B))))) 

:

(DEFINE-COMPILER-MACRO FOOBAR (A B) 
(CONS 'LET 
    (CONS (MAPCAR 'LIST '(A B) (LIST A B)) '((PRINT "foobar") (+ A B))))) 
+0

생성 된 컴파일러 매크로 함수를 호출합니다. "(funcall (컴파일러 매크로 함수 'foobar)'(foobar 10 11)())"매크로 확장 -1 이외에 출력을 확인하는 데 유용한 도구가 될 수 있습니다. –

+0

훌륭한 설명 주셔서 감사합니다! – asm