Проблема двоичного набора - PullRequest
       11

Проблема двоичного набора

1 голос
/ 28 сентября 2011

Я пытаюсь работать с 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 ]

3 голосов
/ 28 сентября 2011

Хотя это немного субъективно, я думаю, что самый чистый и надежный способ исправить это добавить 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 оболочки полностью оптимизированы, поэтому нет никаких накладных расходов во время выполнения.

0 голосов
/ 28 сентября 2011

Не определять экземпляр для Document; просто позвоните getDocument вместо B.get (что, как я вижу, не нужно квалифицировать с B.) в вашем get определении для Collection.

...