2010-07-25 16 views
7

Sto tentando di utilizzare clojure in un compilatore e pertanto è necessario parametrizzare le chiamate su deftype; tuttavia, sto avendo difficoltà a portare a termine i suggerimenti sul tipo. Si consideri il seguente codice:Utilizzo di deflozione Clojure come funzione parametrizzata

(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)))) 

E la seguente sessione dal 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") 

notato che la classe generato per indiretta-tipo ha perso l'^ int accenna che-tipo diretto ha. Come faccio a portare questi suggerimenti?

risposta

7

Avrai bisogno di cambiare indirect-helper a leggere

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

La ragione è che ^int analizza come ^ seguita da int; ^, in Clojure 1.2, introduce i metadati del lettore (in 1.1 si usa #^, che funziona ancora, ma è deprecato in 1.2). Così ^int x in direct ottiene lettura in come clojure.lang.Symbol il cui nome è "x" ei cui metadati mappa è {:tag int} (con il int qui essendo essa stessa un simbolo). (Il componente finale di un simbolo - il suo spazio dei nomi - è nil in questo caso.)

Nella versione del indirect-helper dal testo della domanda ^int si attacca al (symbol "x") - la lista che comprende il simbolo symbol e la stringa "x" (che significa in particolare che (list ^int (symbol "x")) valuta un elenco di 1 elemento). Questo "suggerimento tipo" viene perso una volta valutato (symbol "x"). Per sistemare le cose, è necessario un modo per allegare i metadati al simbolo effettivo generato da (symbol "x").

In questo caso, il simbolo viene generato in fase di runtime, quindi non è possibile utilizzare i metadati del lettore per allegare il suggerimento del tipo ad esso. Inserisci with-meta, che attribuisce i metadati in fase di esecuzione (ed è spesso utile nella scrittura di macro per lo stesso motivo in quanto è qui) e il giorno viene salvato:

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

(BTW, ho pensato deftype aspetta un vettore di nomi dei campi , ma a quanto pare una lista funziona bene ... Un vettore è ancora certamente più idiomatico.)

Problemi correlati