Vic*_*ith 7 haskell derived-instances template-haskell
我一直在试用Vinyl软件包,它使用类型级别来创建具有字段级多态性和自动提供镜头的记录结构.这两个特性对我的项目来说非常方便,因为前者允许记录结构是彼此的子类型而没有名称冲突,后者简化了嵌套结构的更新.
序列化结果结构会产生问题.通常我使用Data.DeriveTH自动派生二进制实例,但它似乎无法应对这些结构.以下代码
{-# LANGUAGE DataKinds, TypeOperators #-}
{-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction #-}
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
import Data.Vinyl
import Data.Binary
import Data.DeriveTH
eID = Field :: "eID" ::: Int
location = Field :: "location" ::: (Double, Double)
type Entity = Rec
[ "eID" ::: Int
, "location" ::: (Double, Double)
]
$(derive makeBinary ''Entity)
Run Code Online (Sandbox Code Playgroud)
导致GHCI出现此错误
Exception when trying to run compile-time code:
Could not convert Dec to Decl
TySynD Main.Entity [] (AppT (ConT Data.Vinyl.Rec.Rec) (AppT (AppT PromotedConsT (AppT (AppT (ConT Data.Vinyl.Field.:::) (LitT (StrTyLit "eID"))) (ConT GHC.Types.Int))) (AppT (AppT PromotedConsT (AppT (AppT (ConT Data.Vinyl.Field.:::) (LitT (StrTyLit "location"))) (AppT (AppT (TupleT 2) (ConT GHC.Types.Double)) (ConT GHC.Types.Double)))) PromotedNilT)))
Language/Haskell/Convert.hs:(37,14)-(40,8): Non-exhaustive patterns in case
Code: derive makeBinary ''Entity
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
这似乎与Derive Convert模块中的这段代码有关:
instance Convert TH.Dec HS.Decl where
conv x = case x of
DataD cxt n vs con ds -> f DataType cxt n vs con ds
NewtypeD cxt n vs con ds -> f NewType cxt n vs [con] ds
where
f t cxt n vs con ds = DataDecl sl t (c cxt) (c n) (c vs) (c con) []
Run Code Online (Sandbox Code Playgroud)
现在我真的不知道怎么读模板Haskell所以我不能在这里取得很大进展.在我看来,我正在喂食一个类型的同义词,而不是一个数据类型,这可能会破坏它,所以我尝试将它包装在一个newtype中:
newtype Entity2 = Entity2 {entity :: Entity}
$(derive makeBinary ''Entity2)
Run Code Online (Sandbox Code Playgroud)
这导致了更加迟钝的错误:
Exception when trying to run compile-time code:
Could not convert Type to Type
AppT (AppT PromotedConsT (AppT (AppT (ConT Data.Vinyl.Field.:::) (LitT (StrTyLit "eID"))) (ConT GHC.Types.Int))) (AppT (AppT PromotedConsT (AppT (AppT (ConT Data.Vinyl.Field.:::) (LitT (StrTyLit "location"))) (AppT (AppT (TupleT 2) (ConT GHC.Types.Double)) (ConT GHC.Types.Double)))) PromotedNilT)
Could not convert Type to Type
AppT PromotedConsT (AppT (AppT (ConT Data.Vinyl.Field.:::) (LitT (StrTyLit "eID"))) (ConT GHC.Types.Int))
Could not convert Type to Type
PromotedConsT
Language/Haskell/Convert.hs:(71,5)-(80,26): Non-exhaustive patterns in function conv
Run Code Online (Sandbox Code Playgroud)
查看Convert.hs,我们有
instance Convert TH.Type HS.Type where
conv (ForallT xs cxt t) = TyForall (Just $ c xs) (c cxt) (c t)
conv (VarT x) = TyVar $ c x
conv (ConT x) | ',' `elem` show x = TyTuple Boxed []
| otherwise = TyCon $ c x
conv (AppT (AppT ArrowT x) y) = TyFun (c x) (c y)
conv (AppT ListT x) = TyList $ c x
conv (TupleT _) = TyTuple Boxed []
conv (AppT x y) = case c x of
TyTuple b xs -> TyTuple b $ xs ++ [c y]
x -> TyApp x $ c y
Run Code Online (Sandbox Code Playgroud)
现在我猜测出了什么问题是GHC 7.6引入了新的语言结构,导致模板Haskell没有考虑到这种结构,导致了非详尽的模式.
所以我的问题是,是否有一些方法可以通过添加到Derive,或者从Vinyl记录类型编写我自己的派生,或类似的东西?如果乙烯基的好处不得不与手写所有序列化进行交易,那将是一种耻辱.
我希望在编写Binary带有所有类型技巧的实例时遇到一些问题,但它不会更容易:
instance Binary (Rec '[]) where
put RNil = return ()
get = return RNil
instance (Binary t, Binary (Rec fs)) => Binary (Rec ((sy ::: t) ': fs)) where
put ((_,x) :& xs) = put x >> put xs
get = do
x <- get
xs <- get
return ((Field, x) :& xs)
Run Code Online (Sandbox Code Playgroud)