質問

次のプログラム例を考えてみましょう。

next :: Int -> Int
next i
  | 0 == m2 = d2
  | otherwise = 3 * i + 1
  where
    (d2, m2) = i `divMod` 2

loopIteration :: MaybeT (StateT Int IO) ()
loopIteration = do
  i <- get
  guard $ i > 1
  liftIO $ print i
  modify next

main :: IO ()
main = do
  (`runStateT` 31) . runMaybeT . forever $ loopIteration
  return ()

使用できるのは get の代わりに lift get なぜなら instance MonadState s m => MonadState s (MaybeT m) はMaybeTモジュールで定義されています。

このようなインスタンスの多くは、一種の組み合わせ爆発方式で定義されます。

それはよかったでしょう(でも不可能ですか?)なぜ?) 次の型クラスがあるとします。

{-# LANGUAGE MultiParamTypeClasses #-}

class SuperMonad m s where
  lifts :: m a -> s a

それを次のように定義してみましょう。

{-# LANGUAGE FlexibleInstances, ... #-}

instance SuperMonad a a where
  lifts = id

instance (SuperMonad a b, MonadTrans t, Monad b) => SuperMonad a (t b) where
  lifts = lift . lifts

使用する lifts $ print i の代わりに liftIO $ print i 動作します、それは良いことです。

しかし、使用して lifts (get :: StateT Int IO Int) の代わりに (get :: MaybeT (StateT Int IO) Int) 機能しません。

GHC (6.10.3) では次のエラーが発生します。

Overlapping instances for SuperMonad
                            (StateT Int IO) (StateT Int IO)
  arising from a use of `lifts'
Matching instances:
  instance SuperMonad a a
  instance (SuperMonad a b, MonadTrans t, Monad b) =>
           SuperMonad a (t b)
In a stmt of a 'do' expression:
    i <- lifts (get :: StateT Int IO Int)

理由はわかります」instance SuperMonad a a」が該当します。しかし、なぜGHCは相手も同様だと考えるのでしょうか?

役に立ちましたか?

解決

ephemient の優れた回答をフォローアップするには、次のようにします。Haskell 型クラスは オープンワールドの想定:バカが後からやって来て、次のようなインスタンス宣言を追加する可能性があります。 重複ではありません そしてまだ と重なる あなたのインスタンス。 敵対ゲームとして考えてください:攻撃者がプログラムを曖昧にする可能性がある場合、コンパイラは動作を停止します。

GHC を使用している場合は、もちろんコンパイラーに「あなたの偏執症は地獄だ」と言うことができます。あいまいなインスタンス宣言を許可してください":

{-# LANGUAGE OverlappingInstances #-}

その後のプログラムの進化により、予想外のオーバーロードが解決された場合、コンパイラーは 1,000 ポイントを獲得します :-)

他のヒント

ちょうどあなたがあなたの現在のモジュールでインスタンスを定義していないので、1つは、どこか別の場所に定義することができなかったことを意味するものではありません。

{-# LANGUAGE ... #-}
module SomeOtherModule where

-- no practical implementation, but the instance could still be declared
instance SuperMonad (StateT s m) m

あなたのモジュールとSomeOtherModuleは、単一のプログラムに一緒にリンクされていると仮定します。

さて、これに答える:ないあなたのコードを使用

instance SuperMonad a a
  -- with a = StateT Int IO

または

instance (SuperMonad a b, MonadTrans t, Monad b) => SuperMonad a (t b)
  -- with a = StateT Int IO
  --      t = StateT Int
  --      b = IO

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top