2012-12-24 8 views
7

Tôi đã thử sử dụng loại Vinyl package, sử dụng loại mức loại để tạo cấu trúc bản ghi với đa hình cấp trường và ống kính được cung cấp tự động. Cả hai tính năng này sẽ rất tiện dụng cho dự án của tôi, vì trước đây cho phép các cấu trúc ghi lại là các kiểu con của nhau mà không có xung đột tên, và sau này đơn giản hóa các cập nhật trên các cấu trúc lồng nhau một cách đáng kể.Có cách nào để phát sinh các trường hợp nhị phân cho các loại bản ghi Vinyl sử dụng Derive và Template Haskell hay không

Sự cố xảy ra với việc nối tiếp cấu trúc kết quả. Thông thường tôi sử dụng Data.DeriveTH để tự động lấy được các thể hiện nhị phân, nhưng nó dường như không thể đối phó với các cấu trúc này. Các mã sau

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

kết quả trong lỗi này trong 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. 

này dường như có liên quan đến đoạn mã này trong lấy được Chuyển đổi mô-đun:

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

Bây giờ tôi don' Tôi thực sự biết cách đọc Mẫu Haskell vì vậy tôi không thể thực hiện nhiều tiến bộ ở đây. Nó xảy ra với tôi rằng tôi đang ăn lấy được một loại từ đồng nghĩa chứ không phải là một kiểu dữ liệu và có thể được phá vỡ nó, vì vậy tôi cố gắng gói nó trong một Newtype:

newtype Entity2 = Entity2 {entity :: Entity} 

$(derive makeBinary ''Entity2) 

dẫn đến lỗi ngay cả tù hơn này:

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 

Nhìn trong Convert.hs chúng tôi có

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 

Bây giờ tôi đoán rằng những gì đang xảy ra sai là GHC 7,6 đã giới thiệu ngôn ngữ mới xây dựng rằng mẫu lấy Haskell không tính đến, dẫn đến các mẫu không đầy đủ.

Vì vậy, câu hỏi của tôi là, có cách nào đó chuyển tiếp bằng cách thêm vào Derive, hoặc viết nguồn gốc của riêng tôi từ các loại bản ghi Vinyl, hoặc một cái gì đó tương tự? Nó sẽ là một sự xấu hổ nếu những lợi ích của Vinyl đã được giao dịch chống lại tay viết tất cả các serialization.

+2

Nó phải có khả năng viết tay các trường hợp một lần cho tất cả các bản ghi Vinyl, tương tự như cách thể hiện của 'Show' được viết. –

+0

Ban đầu tôi nghĩ rằng bạn không thể làm điều đó như thế, ít nhất là không có TH, nhưng bây giờ bạn đề cập đến nó tôi cũng có thể sai. Tôi sẽ có một chuyến đi ... –

Trả lời

7

tôi dự kiến ​​sẽ gặp phải một số vấn đề với văn bản cho Binary hợp với tất cả các loại thủ đoạn gian trá đang xảy ra, nhưng nó không thể nào dễ dàng hơn:

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

Thật tuyệt vời, tôi đã nhận được khoảng một nửa trong đó trong thời gian nó đã đưa bạn, cảm ơn bạn! Hầu như mỗi ngày tôi gặp một lý do mới để yêu thích ngôn ngữ này và cộng đồng của nó. –

+1

(Vinyl creator here!) Thậm chí tôi cũng ngạc nhiên vì điều này dễ như thế nào. Làm tốt lắm, @Sjoerd Visscher! –