二进制打字问题

时间:2011-09-28 09:39:53

标签: haskell bson

我正在尝试使用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方法才能正常工作。

那么,也许有人可以帮助我吗?

2 个答案:

答案 0 :(得分:3)

尽管有点主观,我认为最干净,最有力的解决方法是为newtype添加Document。类似的东西:

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包装器已完全优化,因此在运行时没有开销。

答案 1 :(得分:0)

不要为Document定义实例;只需在getDocument B.get的{​​{1}}定义中调用B.而不是get(我认为不需要使用Collection进行限定)。