2010-07-25 8 views
7

J'essaie d'utiliser clojure dans un compilateur et ai donc besoin de paramétrer les appels à deftype; Cependant, j'ai de la difficulté à faire passer les indications de type. Considérez le code suivant:Utilisation de Clojure deftype en tant que fonction paramétrée

(defn describe [x] 
    (let [fields (.getDeclaredFields x) 
     names (map #(.getName %) fields) 
     types (map #(.getType %) fields)] 
    (interleave types names))) 

(defn direct [] (deftype direct-type [^int x])) 
(defn indirect-helper [] (list ^int (symbol "x"))) 
(defn indirect [] (eval `(deftype ~(symbol "indirect-type") ~(indirect-helper)))) 

Et la session suivante du REPL:

Clojure 1.2.0-master-SNAPSHOT 
1:1 user=> #<Namespace dataclass> 
1:2 dataclass=> (direct) 
dataclass.direct-type 
1:3 dataclass=> (indirect) 
dataclass.indirect-type 
1:4 dataclass=> (describe direct-type) 
(int "x") 
1:5 dataclass=> (describe indirect-type) 
(java.lang.Object "x") 

Notez que la classe générée pour le type indirect a perdu le^int conseils qui-type direct a. Comment puis-je obtenir ces conseils?

Répondre

7

Vous devrez changer indirect-helper lire

(defn indirect-helper [] [(with-meta (symbol "x") {:tag 'int})]) 

La raison est que ^int parse que ^ suivie int; ^, dans Clojure 1.2, introduit des métadonnées de lecture (en 1.1 vous utiliseriez #^, qui fonctionne toujours, mais est dépréciée en 1.2). Ainsi ^int x en direct obtient lecture dans comme clojure.lang.Symbol dont le nom est "x" et dont la carte métadonnées est {:tag int} (avec le int ici étant lui-même un symbole). (Le dernier élément d'un symbole - son espace de nom - est nil dans ce cas.)

Dans la version de indirect-helper du texte de la question ^int se joint à (symbol "x") - la liste comportant le symbole symbol et la chaîne "x" (ce qui signifie en particulier que (list ^int (symbol "x")) évalue à une liste de 1 élément). Cette "indication de type" est perdue une fois que (symbol "x") est évalué. Pour résoudre les problèmes, il est nécessaire de joindre des métadonnées au symbole réel généré par (symbol "x").

Maintenant, dans ce cas, le symbole est généré lors de l'exécution, de sorte que vous ne pouvez pas utiliser les métadonnées de lecteur pour attacher l'indice de type à elle. Entrez with-meta, qui fixe les métadonnées lors de l'exécution (et est souvent utile dans l'écriture de macros pour la même raison que c'est ici) et le jour est enregistré:

user> (indirect) 
user.indirect-type 
user> (describe indirect-type) 
(int "x") 

(BTW, je pensais que deftype attendait un vecteur de noms de champs , mais apparemment une liste fonctionne aussi ... Un vecteur est certainement encore plus idiomatique.)

Questions connexes