访问泛型中的记录名称和功能

时间:2016-03-20 21:51:22

标签: haskell generics

我试图找出如何在deriveJSON之后建模的通用推导。我使用记录样式数据构造函数定义了一个简单类型,如下所示:

data T = C1 { aInt::Int, aString::String} deriving (Show,Generic)

我想要做的是定义一个通用的派生函数,它接受上面的数据构造函数,并使用记录名称和函数输出构建器 - 只是一个玩具代码 - 我们想让ABuilder通用所以我们可以将它用于任何具有记录语法的数据类型(例如deriveJSON中的Aeson):

{-# LANGUAGE DeriveGeneric #-}

import GHC.Generics

data T = C1 { aInt::Int, aString::String} deriving (Show,Generic)

-- Some kind of builder output - String here is a stand-in for the
-- builder
class ABuilder a where
  f :: a -> String

-- Need to get the record field name, and record field function 
-- for each argument, and build string - for anything that is not 
-- a string, we need to add show function - we assume "Show" instance 
-- exists
instance ABuilder T where
  f x = ("aInt:" ++ (show . aInt $ x)) ++ "," ++ ("aString:" ++ (aString $ x))

我无法弄清楚如何获取记录名称和功能。这是我在ghci 7.10.3的尝试。我可以获取数据类型名称,但无法弄清楚如何从中获取记录名称和函数。

$ ghci Test.hs 
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( Test.hs, interpreted )
Ok, modules loaded: Main.
*Main> datatypeName . from $ (C1 {aInt=1,aString="a"})
"T"
*Main> :t from (C1 {aInt=1,aString="a"})
from (C1 {aInt=1,aString="a"})
  :: D1
       Main.D1T
       (C1
          Main.C1_0T
          (S1 Main.S1_0_0T (Rec0 Int) :*: S1 Main.S1_0_1T (Rec0 String)))
       x
*Main> 

我将非常感谢如何获取Generics中的记录名称和功能。如果TemplateHaskell是定义Generic ABuilder实例的更好方法,我将很感激您的原因。如果解决方案很简单,我希望坚持Generics在编译时解决这个问题。我注意到Aeson使用TemplateHaskell作为deriveJSON部分。这就是我之前关于TemplateHaskell的问题,看看我是否遗漏了这些内容(我使用ghc 7.10.3并且不需要与旧版本向后兼容)。

1 个答案:

答案 0 :(得分:2)

这里有一些我刚刚掀起的东西如果你把它交给特定构造函数的内部应该得到这个:

{-# LANGUAGE DeriveGeneric, TypeOperators, FlexibleContexts, FlexibleInstances #-}

import GHC.Generics

data T = C1 { aInt::Int, aString::String} deriving (Show,Generic)

class AllSelNames x where
    allSelNames :: x -> [String]

instance (AllSelNames (a p), AllSelNames (b p)) => AllSelNames ((a :*: b) p) where
    allSelNames (x :*: y) = allSelNames x ++ allSelNames y

instance Selector s => AllSelNames (M1 S s f a) where
    allSelNames x = [selName x]

从repl我们看到

*Main> let x = unM1 . unM1 $ from (C1 {aInt=1,aString="a"})
*Main> allSelNames x
["aInt","aString"]