2017-05-07 2 views
1

Dans Gambit Scheme, je n'arrive pas à invoquer une macro dans la définition d'une autre macro si je compile le fichier. Voici un exemple artificiel:La macro d'appel macro donne "variable indéfinie" dans Gambit Scheme

;;;; example.scm 

(define-macro (w/gensyms gs body) 
    `(let ,(map (lambda (g) `(,g (gensym ',g))) 
       gs) 
    ,body)) 

(define-macro (compose-macro f g) 
    (w/gensyms (x) 
    `(lambda (,x) (,f (,g ,x))))) 

(define my-cadr 
    (lambda (x) 
    ((compose-macro car cdr) x))) 

;; $ gsc example.scm 
;; *** ERROR IN #<procedure #2> -- Unbound variable: w/gensyms 

Cependant, si je charge le fichier avec la (include ...) forme spéciale dans l'interpréteur, il fonctionne

$ gsi 
> (include "example.scm") 
> (pp my-cadr) 
(lambda (x) ((lambda (#:x0) (car (cdr #:x0))) x)) 

Est-ce que quelqu'un sait ce qui se passe ici? Puis-je convaincre Gambit de me laisser utiliser w/gensyms dans la définition d'une autre macro dans un fichier compilé?

+0

Je comprends que je ne devrais pas utiliser define-macro – scpayson

Répondre

0

Ceci est probablement lié aux phases.

Essayez ceci:

Mettez w/gensyms dans un a.scm de fichier et mettre compose-macro dans un b.scm de fichier qui importe a.scm.

+0

import Comment? Selon le manuel gambit, j'ai besoin d'utiliser 'include' pour fusionner dans les définitions de macro. – scpayson

+0

Si je comprends bien, Gambit utilise un système de modules appelé Black Hole: http://dynamo.iro.umontreal.ca/wiki/images/3/30/Black_Hole_Core.pdf – soegaard

0

Ceci est un problème de mise en phase. Vous voulez que la définition de w/gensyms soit disponible dans le corps des macros suivantes. Ceci peut être réalisé avec une macro pour la syntaxe qui force l'évaluation de la définition de la macro au moment de l'extension de la syntaxe:

(define-macro (for-syntax . body) 
    (eval `(begin ,@body)) 
    `(begin)) 

(for-syntax 
(define-macro (w/gensyms gs body) 
    `(let ,(map (lambda (g) `(,g (gensym ',g))) 
       gs) 
     ,body))) 

Si vous voulez que la macro soit disponible à la fois à l'intérieur d'autres définitions de macros et dans la définition non-macro code, vous pouvez utiliser ceci:

(define-macro (for-syntax . body) 
    (eval `(begin ,@body)) 
    `(begin ,@body)) 

Pour cet exemple précis, puisque vous utilisez la macro à un seul endroit, vous auriez pu faire ceci:

(define-macro (compose-macro f g) 

    (define-macro (w/gensyms gs body) 
    `(let ,(map (lambda (g) `(,g (gensym ',g))) 
       gs) 
     ,body)) 

    (w/gensyms (x) 
    `(lambda (,x) (,f (,g ,x))))) 

Une approche pour résoudre les problèmes liés à l'élimination progressive est de mettre la définition de w/gensyms et d'autres macros dans le fichier « macros.scm » et faire:

(define-macro (compose-macro f g) 

    (include "macros.scm") 

    (w/gensyms (x) 
    `(lambda (,x) (,f (,g ,x)))))