2012-12-24 7 views
7

フィールドレベルの多態性を持つレコード構造を作成するためにタイプレベルの種類を使用し、レンズを自動的に提供するVinyl packageを試しています。前者は名前の衝突なしに互いにサブタイプのレコード構造を可能にし、後者はネストされた構造の更新を劇的に簡素化するので、これらの機能はどちらも私のプロジェクトにとって非常に便利です。DeriveとTemplate Haskellを使用してVinylレコードタイプのバイナリインスタンスを派生させる方法はありますか?

問題は結果として生じる構造を直列化することに伴い発生します。通常、私はDataDeriveTHを使って自動的にバイナリインスタンスを派生させますが、これらの構造に対処できないようです。 「今

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) [] 

私はドン:GHCiの中にこのエラーに次のコードは、

{-# 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) 

結果は

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. 

これは、モジュール変換派生のコードのこの部分に関連しているようですTemplate Haskellの読み方を本当に知っているので、私はここで進歩を遂げることができません。私がデータ型ではなく、型シノニムを導き出す供給していますし、それはそれを破ることができたので、私はnewtypeの中でそれをラップしようとしたことを私に発生しました:この一層鈍角エラーにつながる

newtype Entity2 = Entity2 {entity :: Entity} 

$(derive makeBinary ''Entity2) 

私たちは今、私は何を間違って起こっていることはGHC 7.6は、新しい言語が由来テンプレートHaskellのことを構築し導入したことであることを

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 

を推測しているConvert.hsで探し

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 

考慮していないので、網羅的ではないパターンにつながります。

私の質問は、Deriveに追加すること、またはVinylレコードタイプなどから派生したものを書くことです。ビニールのメリットがすべてのシリアル化を手書きで書き換えなければならないのは残念です。

+2

一回のインスタンスを書く手することが可能ですすべてのVinylレコードは、 'Show'インスタンスがどのように書かれているかと似ています。 –

+0

私はもともと、あなたはTHのようにそれをすることができないと思っていましたが、少なくともTHなしではできませんでした。私は行くだろう... –

答えて

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) 
+3

それは素晴らしいです、私はそれがあなたを取った時に途中で得た、ありがとう!ほとんど毎日、私はこの言語とそのコミュニティを愛する新しい理由に出会う。 –

+1

(ビニールのクリエイターはこちら!)でも、これがいかに簡単かは驚きです。素敵な仕事、@ Sjoerd Visscher! –

関連する問題