2017-06-24 5 views
6

Identityのモナドトランスタイプを定義すると、Showインスタンスを導出できます。MaybeTのShowインスタンスを派生させることができないのはなぜですか?

newtype IdentityT f a = 
    IdentityT { runIdentityT :: f a } 
    deriving (Show) 

instance Show (f a) => Show (IdentityT f a) 

を導出します。しかし、私はMaybe

newtype MaybeT m a = 
    MaybeT { runMaybeT :: m (Maybe a) } 
    deriving (Show) 

のためのモナド変換子のタイプを定義する場合、私はので、エラー

• No instance for (Show (m (Maybe a))) 
     arising from the first field of ‘MaybeT’ (type ‘m (Maybe a)’) 

を取得します0がShowインスタンスを持って、私はそれが仕事と導くために期待する

instance Show (m (Maybe a)) => Show (MaybeT m a) 

なぜできないのですか?

答えて

3

GHCはヒューリスティックを使用して、インスタンスが検索終了を保証するかどうかを判断します。 ここで終了すると、インスタンスを検索するときに永遠にループしないことを意味します。具体的には、これは

instance Show a => Show a where ... 

ならびにこの

instance Show [a] => Show a where ... 

GHCが略インスタンスのコンテキスト(=>前部分)に制約がで制約よりも「小さい」ものでなければならないことを要求する禁止されなければなりません頭部(=>の後)。だから、それはこれを受け入れ:

instance Show a => Show [a] where ... 

a[a]未満1型コンストラクタが含まれているため。

また、この受け入れ:f aIdentityT f a未満1型コンストラクタが含まれているので

instance Show (f a) => Show (IdentityT f a) where ... 

を。

しかし、

instance Show (f (Maybe a)) => Show (MaybeT f a) where ... 

は、コンストラクタの同じ番号を使用しています!したがって、ループが発生しないことを確認することはできません。結局、後に、私たちは

instance Show (MaybeT f a)) => Show (f (Maybe a)) where ... 

を満たす可能性があり、それはこれらの2つのインスタンスの少なくとも一方が終了を保証するために拒否しなければならないことは明らかです。GHCは、両方を拒否することを選択します。

UndecidableInstancesこの制限を緩和します。 GHCは両方のインスタンスを受け入れ、ループを回避するために私たちに負担がかかります。

5

は、私たちは行き止まりにヒットするまで、我々は(私は8.2.1を使用しています)GHCの提案に従うことによって、問題を見ることができると思う:

Prelude> :{ 
Prelude| newtype MaybeT m a = 
Prelude| MaybeT { runMaybeT :: m (Maybe a) } 
Prelude| deriving (Show) 
Prelude| :} 

<interactive>:12:13: error: 
    • No instance for (Show (m (Maybe a))) 
     arising from the first field of ‘MaybeT’ (type ‘m (Maybe a)’) 
     Possible fix: 
     use a standalone 'deriving instance' declaration, 
      so you can specify the instance context yourself 
    • When deriving the instance for (Show (MaybeT m a)) 
Prelude> :set -XStandaloneDeriving 
Prelude> deriving instance Show (m (Maybe a)) => Show (MaybeT m a) 

<interactive>:17:19: error: 
    • The constraint ‘Show (m (Maybe a))’ 
     is no smaller than the instance head 
     (Use UndecidableInstances to permit this) 
    • In the stand-alone deriving instance for 
     ‘Show (m (Maybe a)) => Show (MaybeT m a)’ 

大丈夫、そうShowため導き出せるためMaybeTありそうでありませんでしたその制約は、タイプチェッカーが終了を証明できないという制約の一種であるため、許可されませんでした。この答えで「インスタンスヘッドより小さくない」という意味のことをもっと読むことができます:https://stackoverflow.com/a/17866970/176841

+1

しかし、その2番目の提案は、 'UndecidableInstances'を有効にするためには問題ありません。 – dfeuer

+0

私は 'UndecidableInstances'を使ってコンパイラにインスタンスを派生させることができますが、' MaybeT'型では 'IdentityT'型をうまく処理できる間にそれを派生させることができません。 Ex。私はそれが 'MaybeT [Just1]'を拡張子なしで表示できると期待しています – robertjlooby

関連する問題