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

newtype少し主観的ですが、修正するための最もクリーンで堅牢な方法は、 forを追加することだと思います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

のインスタンスを定義しないでくださいDocumentgetDocumentの代わりにB.get( で修飾する必要はないと思いB.ます) を のget定義で呼び出すだけですCollection

于 2011-09-28T09:59:17.527 に答える