2009-08-25 4 views
4

J'essaie d'écrire une macro dans clojure qui configure un espace de noms et y ajoute automatiquement quelques méthodes. Ma macro ne fonctionnait pas et j'ai suivi jusqu'à une déclaration de do. Il n'est pas possible de déclarer un nouvel espace de noms dans un do et immédiatement après déclarer une méthode dans cet espace de noms. Pourquoi?pourquoi je ne peux pas déclarer un espace de noms et une méthode dans un do en utilisant Clojure

Cela ne fonctionne pas:

(ns xyz) 
(do 
    (ns abc) 
    (prn *ns*) 
    (defn tst[] (prn "test" *ns*))) 

(prn "after" *ns*) 
(tst) 

Cela fonctionne (déclaration d'espace de noms avant le do):

(ns xyz) 
(ns abc) 
(do 
    (prn *ns*) 
    (defn tst[] (prn "test" *ns*))) 

(prn "after" *ns*) 
(tst) 

Merci pour la lecture, Markus

Répondre

7

En fait votre code fonctionne avec Clojure> 1.0 mais ne comptez pas dessus! Chaque forme de niveau supérieur est compilé puis exécuté:

(ns xyz) ; compiled with current ns/exec sets the current ns to xyz 
(do ; the whole form is compiled inthe current ns (xyz) so it defines xyz/tst 
    (ns abc) 
    (prn *ns*) 
    (defn tst[] (prn "test" *ns*))) 
; the form above is executed: it sets the new current ns 
; and the value for xyz/tst 

(prn "after" *ns*) ; we are in abc 
(tst) ; abc/tst doesn't exists 

En clojure> 1.0, un faire un niveau supérieur est « déroula » de sorte que votre code est maintenant équivalent à:

(ns xyz) 
; (do 
(ns abc) 
(prn *ns*) 
(defn tst[] (prn "test" *ns*));) 

(prn "after" *ns*) 
(tst) 
+0

Ah merci. Ceci explique cela. Je garderai ceci à l'esprit simplement à la macro une fois qu'une version de clojure stable> 1.0 sera disponible. –

1

Son problème de « l'expansion macro temps "temps contre" temps d'exécution ". Souhaitez-vous que le code apparaisse lorsque le programme est compilé ou lorsque le programme est exécuté par l'utilisateur?
les lignes (ns ...) sont développées par le lecteur puis utilisées par le compilateur pour décider où Si je comprends bien, ns définit la liaison de niveau supérieur de la variable var qui indique au compilateur l'espace de nom pour lequel il construit le code. (... prn) expression devrait entrer.

4

Votre code ne fait pas ce que vous pensez probablement qu'il fait. la fonction tst imprime la valeur de * ns *, un var, au moment où la fonction est exécuter, pas quand il est défini.

user> (ns foobar) 
nil 
foobar> (abc/tst) 
"test" #<Namespace foobar> 
nil 
foobar> (ns zelsbot) 
nil 
zelsbot> (abc/tst) 
"test" #<Namespace zelsbot> 
nil 

Ce que vous essayez de faire a déjà été bien fourni par clojure.contrib.with-ns:

(ns xyz 
    (:use clojure.contrib.with-ns)) 

(with-ns (create-ns 'abc) 
    (defn tst [] (print "defined in namespace abc"))) 

Il évalue son corps dans l'espace de noms que vous fournissez comme premier argument, vous permettant ainsi d'ajouter des fonctions à un namespace autre que celui en cours.

+0

qui a été signifié comme un test d'exécution. De toute façon votre conseil avec-ns est très utile car je peux l'utiliser pour obtenir la fonctionnalité désirée. –

Questions connexes