10

次のサンプルプログラムについて考えてみます。

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 ()

MaybeTモジュールで定義されているため、get代わりにのみ使用できます。lift getinstance MonadState s m => MonadState s (MaybeT m)

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

次の型クラスがあれば、それは良かったでしょう(不可能ではありますか?なぜですか?)。

{-# 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は、もう一方もそうだと考えているのでしょうか。

4

3 に答える 3

37

ephemient の優れた回答をフォローアップするには: Haskell 型クラスはオープンワールドの仮定を使用します: 一部の馬鹿が後でやって来て、重複していないがインスタンス重複するインスタンス宣言を追加する可能性があります。 これを敵対的なゲームと考えてください。敵対者がプログラムをあいまいにすることができる場合、コンパイラはブリートします。

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

{-# LANGUAGE OverlappingInstances #-}

あなたのプログラムのその後の進化があなたが予期していなかったオーバーロードの解決につながる場合、コンパイラは1,000ポイントを獲得します:-)

非推奨メモ

このプラグマはGHC 7.10以降非推奨となり、代わりにインスタンスごとのプラグマを使用する必要があります。詳細については、GHC のドキュメントを参照してください。

于 2009-07-02T04:38:17.470 に答える
8

現在のモジュールでインスタンスを定義していないからといって、他の場所でインスタンスを定義できなかったわけではありません。

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

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

モジュールとSomeOtherModuleが 1 つのプログラムにリンクされているとします。

今、これに答えてください:あなたのコードは使用していますか

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

?

于 2009-06-30T16:55:19.313 に答える