Я пробовал пакет 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)
приводит к этой ошибке в 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.
Кажется, это связано с этим фрагментом кода в модуле 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) []
Теперь я действительно не знаю, как читать Template Haskell, поэтому я не могу добиться здесь большого прогресса. Мне пришло в голову, что я подаю производный синоним типа, а не тип данных, и это может его сломать, поэтому я попытался обернуть его в новый тип:
newtype Entity2 = Entity2 {entity :: Entity}
$(derive makeBinary ''Entity2)
что приводит к этой еще более тупой ошибке:
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
Глядя в 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
Теперь я предполагаю, что что-то идет не так, потому что GHC 7.6 представил новые языковые конструкции, которые шаблон Derive Haskell не принимает во внимание, что приводит к неисчерпывающим шаблонам.
Итак, мой вопрос: есть ли какой-то путь вперед, либо добавление к производному, либо написание моего собственного производного от типов виниловых пластинок, или что-то подобное? Было бы позором, если бы преимущества винила пришлось пожертвовать ручным написанием всей сериализации.
Show
. - person Sjoerd Visscher   schedule 24.12.2012