【问题标题】:Haskell introspecting a record's field names and typesHaskell 内省记录的字段名称和类型
【发布时间】:2012-01-30 21:10:26
【问题描述】:

基于recent exchange,我被说服使用 Template Haskell 生成一些代码以确保编译时类型安全。

我需要自省记录字段名称和类型。我知道我可以通过使用constrFields . toConstr :: Data a => a -> [String]get field names。但我需要的不仅仅是字段名称,我还需要知道它们的类型。例如,我需要知道 Bool 类型的字段的名称。

如何构造函数f :: a -> [(String, xx)],其中a 是记录,String 是字段名称,xx 是字段类型?

【问题讨论】:

    标签: haskell template-haskell


    【解决方案1】:

    reify 提供的Info 值中应该可以使用该类型以及其他所有内容。具体来说,你应该得到一个TyConI,其中包含a Dec value,你可以从中得到Con values specifying the constructors的列表。然后记录类型应该使用RecC,这将为您提供包含字段名称、字段是否严格以及the type 的字段列表described by a tuple

    你从那里去哪里取决于你想用这一切做什么。


    编辑:为了实际演示上述内容,这里有一个非常糟糕的快速而肮脏的函数,它可以找到记录字段:

    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)
    

    在另一个模块中导入它,我们可以这样使用它:

    data Foo = Foo { foo1 :: Int, foo2 :: Bool }
    
    foo = $(test ''Foo)
    

    在 GHCi 中加载,foo 中的值为[("Foo",[("foo1","ConT GHC.Types.Int"),("foo2","ConT GHC.Types.Bool")])]

    这会给你一个粗略的想法吗?

    【讨论】:

    • 这正是我正在寻找的。我将您的示例归结为以下内容:introspect n = reify n &gt;&gt;= stringE . show。感谢您的指导!
    猜你喜欢
    • 2019-07-02
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    • 2012-01-17
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多