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?
Questo è esattamente quello che sto cercando. Ho ridotto l'esempio al seguente: 'introspect n = reify n >> = stringE. show'. Grazie per la guida! – Ana