2011-09-28 114 views
1

我想與Haskell Bson一起工作,我想保存並加載它們。保存似乎沒有問題,但我在Binary.get函數中出現打字錯誤。二進制鍵入問題

這裏是我的代碼:

{-# LANGUAGE GeneralizedNewtypeDeriving, TypeSynonymInstances, FlexibleInstances #-} 
module Database.Axiom where 

import Data.Bson (Document, Field) 
import Data.Bson.Binary (putDocument, getDocument) 
import Data.Binary as B (Binary(..), decodeFile, encodeFile) 
import Control.Monad (liftM2) 

instance Binary Document where 
    put = putDocument 
    get = getDocument 

data Collection = Collection { 
     collectionName :: ByteString, 
     collectionDocs :: [Document] 
    } 

instance Binary Collection where 
    put (Collection name docs) = B.put name >> B.put docs 
    get = liftM2 Collection B.get B.get -- < Here is the type error 

導致這個錯誤:

Database/Axiom.hs:24:39: 
    Overlapping instances for Binary [Field] 
     arising from a use of `B.get' 
    Matching instances: 
     instance Binary a => Binary [a] -- Defined in Data.Binary 
     instance Binary Document -- Defined at Database/Axiom.hs:13:10-24 
    In the third argument of `liftM2', namely `B.get' 
    In the expression: liftM2 Collection B.get B.get 
    In an equation for `get': get = liftM2 Collection B.get B.get 

問題是Document僅僅是[Field]的代名詞。但我需要一個Binary Document的實例,因爲沒有函數可以序列化一個Field。此外,BSON不會爲Binary Field導出任何實例,所以我完全困惑爲什麼這個錯誤首先發生。

我有嚴格的類型聲明試了一下,然後用一個自制get方法,但僅get :: [Document]很好地工作時,有一個get :: Document方法。

那麼,任何人都可以幫助我,也許?

回答

3

雖然有點主觀,但我認爲最簡潔最穩健的方法是爲Document添加newtype。例如:

import Control.Applicative ((<$>)) 
import Data.ByteString (ByteString) 
import Data.Bson (Document, Field) 
import Data.Bson.Binary (putDocument, getDocument) 
import Data.Binary as B (Binary(..), decodeFile, encodeFile) 
import Control.Monad (liftM2) 

newtype CollectionDoc = CollectionDoc {unCollectionDoc :: Document} 

instance Binary CollectionDoc where 
    put = putDocument . unCollectionDoc 
    get = CollectionDoc <$> getDocument 

data Collection = Collection { 
     collectionName :: ByteString, 
     collectionDocs :: [CollectionDoc] 
    } 

instance Binary Collection where 
    put (Collection name docs) = B.put name >> B.put docs 
    get = liftM2 Collection B.get B.get 

應該工作。此外,newtype包裝完全優化,所以在運行時沒有開銷。

0

請勿爲Document定義實例;只需撥打getDocument而不是B.get(我認爲您不需要使用B.進行資格認證)就可以在Collectionget定義中找到。

+0

這不起作用,因爲第二個'get'的類型是'Get [Document]'。 – Lanbo

+0

@Scán:哦,對,錯過了:/ – ivanm

+0

@Scán:'[getListOf](http://hackage.haskell.org/packages/archive/cereal/0.3.3.0/doc/html/Data-Serialize-Get .html#v:getListOf)getDocument'會做的伎倆,然後如果你不想像jaspervdj描述的新類型。 – ivanm