我正在尝试使用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
方法才能正常工作。
那么,也许有人可以帮助我吗?
答案 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
进行限定)。