我试图找出如何在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
并且不需要与旧版本向后兼容)。
答案 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"]