2012-12-24 5 views
7

Próbowałem od Vinyl package, który wykorzystuje rodzaje rodzajów poziomów do tworzenia struktur rekordów z polimorfizmem na poziomie pola i automatycznie dostarczanymi obiektywami. Obie te funkcje byłyby bardzo przydatne w moim projekcie, ponieważ pierwsza z nich pozwala na tworzenie rekordowych struktur, które są pod-typami bez konfliktów nazw, a ta ostatnia znacznie upraszcza aktualizacje zagnieżdżonych struktur.Czy istnieje sposób na wyprowadzenie wystąpień binarnych dla typów rekordów winylowych przy użyciu wyliczeń i szablonów Haskell lub w inny sposób

Problem polega na szeregowaniu uzyskanych struktur. Zwykle używam Data.DeriveTH do automatycznego generowania instancji binarnych, ale wydaje się, że nie poradzę sobie z tymi strukturami. Poniższy kod

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

skutkuje tym błędem w 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. 

To wydaje się być związane z tego kawałka kodu w dryfu Konwersja moduł:

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

Teraz don” t naprawdę wiesz, jak czytać szablon Haskell, więc nie mogę zrobić tutaj dużego postępu. Przyszło mi do głowy, że ja karmię czerpać typu synonim zamiast typu danych i że może być złamanie go, więc próbowałem owijając go w newtype:

newtype Entity2 = Entity2 {entity :: Entity} 

$(derive makeBinary ''Entity2) 

co prowadzi do tego jeszcze bardziej rozwarty błędu:

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 

Patrząc w Convert.hs mamy

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 

teraz Zgaduję, że to, co jest nie tak, że GHC 7.6 wprowadzono nowy język konstruuje że szablon Derive Haskell nie bierze pod uwagę, prowadząc do niewyczerpujących wzorców.

Moje pytanie brzmi, czy istnieje jakiś sposób na to, czy dodać do Derive, czy napisać własne pochodzenie z typów płyt winylowych, czy coś podobnego? Szkoda byłoby, gdyby korzyści płynące z winyla wymknęły się spod ręki, pisząc całą serializację.

+2

powinna istnieć możliwość przekazania napisać instancje raz wszystkie zapisy winylowe, podobne do tego, w jaki sposób napisano instancję 'Show'. –

+0

Początkowo myślałem, że nie możesz tego zrobić, przynajmniej nie bez TH, ale teraz wspomniałeś, że mogę się mylić. Będę musiał ... –

Odpowiedz

7

spodziewałem się napotkać pewne problemy z pisania Binary wystąpień ze wszystkimi rodzaj oszustwa dzieje, ale to nie może być prostsze:

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

To niesamowite, w tamtym czasie dotarłem w połowie drogi, dziękuję! Niemal każdego dnia spotykam nowy powód, by kochać ten język i jego społeczność. –

+1

(Vinyl Creator tutaj!) Nawet jestem zaskoczony, jak łatwo było. Dobra robota, @Sjoerd Visscher! –

Powiązane problemy