2011-12-30 9 views
8

Basato su un recent exchange, sono stato convinto di utilizzare Template Haskell per generare del codice per garantire la sicurezza del tipo in fase di compilazione.Haskell che introspecting i nomi dei campi di un record e tipi

Ho bisogno di analizzare i nomi dei campi e i tipi di record. Capisco che posso get field names utilizzando constrFields . toConstr :: Data a => a -> [String]. Ma ho bisogno di più dei nomi dei campi, ho bisogno di sapere il loro tipo. Ad esempio, ho bisogno di conoscere i nomi dei campi che sono di tipo Bool.

Come faccio a costruire una funzione f :: a -> [(String, xx)] dove a è il record, String è il nome del campo e xx è il tipo di campo?

risposta

8

Il tipo deve essere disponibile, insieme a tutto il resto, nel valore Info fornito da reify. Nello specifico, è necessario ottenere uno TyConI, che contiene a Dec value, da cui è possibile ottenere l'elenco di Con values specifying the constructors. Un tipo di record dovrebbe quindi utilizzare RecC, che fornirà un elenco di campi described by a tuple contenenti il ​​nome del campo, se il campo è rigido e the type.

Dove vai da lì dipende da cosa vuoi fare con tutto questo.


Edit: Per il bene della realtà che dimostra quanto sopra, ecco una davvero terribile funzione di rapido e sporco che trova campi dei record:

import Language.Haskell.TH 

test :: Name -> Q Exp 
test n = do rfs <- fmap getRecordFields $ reify n 
      litE . stringL $ show rfs 

getRecordFields :: Info -> [(String, [(String, String)])] 
getRecordFields (TyConI (DataD _ _ _ cons _)) = concatMap getRF' cons 
getRecordFields _ = [] 

getRF' :: Con -> [(String, [(String, String)])] 
getRF' (RecC name fields) = [(nameBase name, map getFieldInfo fields)] 
getRF' _ = [] 

getFieldInfo :: (Name, Strict, Type) -> (String, String) 
getFieldInfo (name, _, ty) = (nameBase name, show ty) 

importazione che in un altro modulo, possiamo usarlo in questo modo:

data Foo = Foo { foo1 :: Int, foo2 :: Bool } 

foo = $(test ''Foo) 

Loading che nel GHCi, il valore in foo è [("Foo",[("foo1","ConT GHC.Types.Int"),("foo2","ConT GHC.Types.Bool")])].

Questo ti dà un'idea approssimativa?

+0

Questo è esattamente quello che sto cercando. Ho ridotto l'esempio al seguente: 'introspect n = reify n >> = stringE. show'. Grazie per la guida! – Ana

Problemi correlati