7

タイプレベルの種類を使用して、フィールドレベルのポリモーフィズムと自動的に提供されるレンズを備えたレコード構造を作成するVinyl パッケージを試しています。これらの機能はどちらも私のプロジェクトにとって非常に便利です。前者は名前の衝突なしに互いのサブタイプであるレコード構造を許可し、後者はネストされた構造の更新を劇的に簡素化するからです。

問題は、結果の構造をシリアライズすることです。通常は Data.DeriveTH を使用して自動的に Binary インスタンスを派生させますが、これらの構造に対応できないようです。次のコード

{-# 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 が考慮していない新しい言語構造を導入し、非網羅的なパターンにつながっていることが問題になっていると思います。

だから私の質問は、派生に追加するか、ビニールレコードタイプから独自の派生を書くか、または同様のものを作成することによって、前進する方法はありますか? ヴァイナルの利点と、すべての連載を手書きすることとをトレードオフしなければならなかったとしたら、それは残念なことです。

4

1 に答える 1

7

すべての型の策略が行われている状態でインスタンスを作成すると、いくつかの問題に遭遇することが予想されました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)
于 2012-12-24T12:16:03.413 に答える