2016-10-01 4 views
0

私は、コンパイラは次のコード(コードのコンパイル)文句ないことに困惑している:私は、例えば、どこかの制約としてMonadIO mを追加する必要がありました場合にはすぐに、再び私には理にかなってなぜMonadスタックは一般的にMonadIOを派生しますか?

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

module Main where 

import Control.Monad.IO.Class (MonadIO) 
import Control.Monad.Except (ExceptT) 

main = undefined 

newtype Foo e m a = Foo { unFoo :: ExceptT e m a } 
    deriving (Functor, Applicative, Monad, MonadIO) 

deriving instance MonadIO m => MonadIO (Foo e m a) 

と確かに私は

deriving instance MonadIO (Foo e m a), 

をしようとした場合、コンパイラは文句を言います。

MonadIO mという制約を追加するときにはliftIOしか使用できないことに気付きました。スタンドアロンの派生と制約でメソッド2を使用しているかどうかにかかわらず、やはり意味があります。 MonadIOのインスタンスはの条件でであり、MonadIO mです。

私はそれだけですか、それとも直感的ですか?

廃止予定の-XDatatypeContexts拡張機能と関連がありますか? GeneralizedNewtypeDeriving

答えて

1

、すべてのインスタンスが同じ制約を持つ - newtypeの基本型は、同じクラスのインスタンスでなければなりません:

Generalised derived instances for newtypes

All the instance does is apply and remove the newtype constructor.

の派生インスタンス、つまりMonadは制約があります既に存在するMonad (ExceptT e m)です。ただし、MonadIO (ExceptT e m)のインスタンスは存在しないため、結果として生じるMonadIO宣言の制約条件でなければなりません。

私は使用MonadIO (Foo e m)にしようとすると、エラーが生成されます。

something :: Foo e m() 
something = liftIO $ print "5" 

ここでエラーです:

• No instance for (MonadIO m) arising from a use of ‘liftIO’ 
     Possible fix: 
     add (MonadIO m) to the context of 
      the type signature for: 
      something :: Foo e m() 
    • In the expression: liftIO $ print "5" 
     In an equation for ‘something’: something = liftIO $ print "5" 
+0

私はそれを認識しています。しかし、なぜこれはとても扱いにくいのですか?例えば。私が 'MonadError e'を派生させたとき、後で制約を加える必要はありません。 –

+0

'MonadError e'は全ての' m'に対して有効な 'ExceptT'からの実装が使われるので、' m'に制約を必要としません。 'MonadIO'は' m'の実装を使用する必要があり、そのような実装が存在することを保証しなければならないので、 'm'の制約なしに実装することはできません。それは厄介ではなく、少なくともそれが必要とするほど厄介です。 –

+0

ドキュメントへのリンクを追加しました。 – Koterpillar

関連する問題