2011-12-30 15 views
8

Na podstawie recent exchange, byłem przekonany, aby użyć szablonu Haskell do wygenerowania kodu zapewniającego bezpieczeństwo podczas kompilacji.Haskell introspekcja nazw i typów pól rekordów

Potrzebuję do introspekcji rekordów nazw i typów pól. Rozumiem, że mogę get field names za pomocą constrFields . toConstr :: Data a => a -> [String]. Ale potrzebuję więcej niż nazwy pól, muszę znać ich typ. Na przykład muszę znać nazwy pól typu Bool.

Jak skonstruować funkcję f :: a -> [(String, xx)] gdzie a jest zapis, String to nazwa pola i xx jest typ pola?

Odpowiedz

8

Typ powinien być dostępny, wraz ze wszystkim innym, w wartości Info dostarczonej przez reify. W szczególności powinieneś uzyskać numer TyConI, który zawiera a Dec value, z którego możesz uzyskać listę Con values specifying the constructors. Typ rekordu powinien następnie użyć RecC, co da ci listę pól described by a tuple zawierającą nazwę pola, czy pole jest ścisłe, i the type.

Dokąd pójdziesz, zależy od tego, co chcesz zrobić z tym wszystkim.


Edit: Dla faktycznie wykazując wyżej, tutaj jest naprawdę straszny szybki i brudny funkcją, która wyszukuje pola rekordu:

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) 

Importowanie że w innym module, możemy go użyć tak:

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

foo = $(test ''Foo) 

Ładowanie że w GHCi wartość w foo jest [("Foo",[("foo1","ConT GHC.Types.Int"),("foo2","ConT GHC.Types.Bool")])].

Czy to daje zły pomysł?

+0

Dokładnie tego szukam. Przygotowałem twój przykład do następujących rzeczy: 'introspect n = reify n >> = stringE. show'. Dzięki za wskazówki! – Ana

Powiązane problemy