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

那么,任何人都可以帮助我,也许?

4

2 回答 2

3

虽然有点主观,但我认为最干净和最强大的修复方法是添加一个newtypefor 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包装器被完全优化掉,因此在运行时没有开销。

于 2011-09-28T09:57:34.710 回答
0

不要为Document;定义实例 只需在您的定义中调用getDocument而不是B.get(我认为不需要使用.B.getCollection

于 2011-09-28T09:59:17.527 回答