0

拡張可能なシリアル化ライブラリのアイデアをいじっています。次の型クラスがあります。

class Monoid m => BuilderS m a where
  cstr :: String -> a -> m

アイデアは、次のように、異なるシリアライザー/タイプのペアのインスタンスを定義できるということです。

import qualified Data.Serialize.Builder as B

instance Serialize a => BuilderS B.Builder a where
  cstr _ = B.fromByteString . encode

そして使用例:

sfPut :: (BuilderS a b, Monoid a) => WriterT a Identity ()
sfPut = do
  tell $ cstr "version" (5 :: Int)
  -- ...
  return ()

ただし、 の型をa特殊化する必要があることがわかりました。

Could not deduce (BuilderS a Int) arising from a use of `cstr'
    from the context (BuilderS a b, Monoid a)
      bound by the type signature for
                 sfPut :: (BuilderS a b, Monoid a) => WriterT a Identity ()

つまり、次の型シグネチャは問題なく機能します。

sfPut :: WriterT B.Builder Identity ()

これを解決するために私が見逃している明らかな方法はありますか?

4

1 に答える 1

1

さて、あなたが与えた型クラスを使用する場合は、GHCi を使用して型をチェックします。

> :t tell $ cstr "version" (5 :: Int)
tell $ cstr "version" (5 :: Int) :: (MonadWriter s m, BuilderS s Int) => m ()

BuilderS a Intしたがって、 ではなくであることを指定する必要があるようですBuilderS a b。私が持っている場合

sfPut :: BuilderS a Int => WriterT a Identity ()
sfPut = tell $ cstr "version" (5 :: Int)

それは正常に動作します。これも必要FlexibleContextsであり、型シグネチャ5はオプションではないことに注意してください。


さらに詳しく説明すると、あなたが与えた型シグネチャsfPut

BuilderS m a => WriterT m Identity ()

しかしtell $ cstr "version (5 :: Int)、タイプを持つ用語 がありました

BuilderS m Int => WriterT m Identity ()

a型システムはとを統合できなかったためInt、エラーが発生しました。さらに、 の型シグネチャを省略した場合、5 :: Int代わりに

tell $ cstr "version" 5 :: (Num a, BuilderS m a) => WriterT m Identity ()

しかし、aは に表示されないWriterT m Identity ()ため、型システムは のどのインスタンスNumを使用するかを認識できず5、別のエラーが発生します。具体的には、次のようになります。

> let sfPut = tell $ cstr "version" 5
Could not deduce (BuilderS s a0)
  arising from the ambiguity check for ‘sfPut’
from the context (BuilderS s a, MonadWriter s m, Num a)
  bound by the inferred type for ‘sfPut’:
             (BuilderS s a, MonadWriter s m, Num a) => m ()
  at <interactive>:20:5-35
The type variable ‘a0’ is ambiguous
When checking that ‘sfPut’
  has the inferred type ‘forall (m :: * -> *) s a.
                         (BuilderS s a, MonadWriter s m, Num a) =>
                         m ()’
Probable cause: the inferred type is ambiguous

ただし、代わりにモノモーフィック リテラル (または型がポリモーフィックでない値) を使用すると、簡単に行うことができます。

> let sfPut = tell $ cstr "version" "I'm not polymorphic"
> :t sfPut
sfPut :: (BuilderS s [Char], MonadWriter s m) => m ()
于 2014-08-22T14:26:47.470 に答える