2011-12-30 9 views
8

recent exchangeに基づいて、コンパイル時の型の安全性を保証するためにTemplate Haskellを使用してコードを生成することに納得しました。Haskellがレコードのフィールド名と型を調べる

レコードのフィールド名とタイプを調べる必要があります。私はを使ってget field namesとすることができます。しかし、私はフィールド名以上のものが必要です、私はそのタイプを知る必要があります。たとえば、タイプがBoolのフィールドの名前を知る必要があります。

関数を作成する方法f :: a -> [(String, xx)]ここで、aはレコード、Stringはフィールド名、xxはフィールド型です。

答えて

8

reifyで指定されている値のInfoには、他のものと同様に使用できるようにしてください。具体的にはTyConIがあり、a Dec valueが含まれています。Con values specifying the constructorsのリストを取得できます。レコードタイプはRecCを使用する必要があります。これは、フィールド名が厳密であるかどうかを示すフィールドdescribed by a tupleと、the typeのリストを提供します。

どこから行くのかは、これで何をしたいのかによって異なります。


編集:他のモジュールでは、我々はそれを使用することができインポート

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) 

:実際に上記を実証するために、ここでレコードフィールドを見つけた本当にひどい、拙速な機能です以下のようなので:GHCiの中で、fooの値が[("Foo",[("foo1","ConT GHC.Types.Int"),("foo2","ConT GHC.Types.Bool")])]であることを

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

foo = $(test ''Foo) 

読み込ん。

これは大まかなアイデアですか?

+0

これはまさに私が探しているものです。私はあなたの例を次のように煮詰めました: 'introspect n = reify n >> = stringE。ショー。ガイダンスをありがとう! – Ana

関連する問題