2017-11-22 12 views
3

私は数日前にフリーモナドのコンテキストでファンクタを注入することについてI asked a questionです。 Data Types à la Carteに基づいて、そこに提案されている解決策は、ファンクタ間の一種の包含関係を表すクラスを使用します。これらの2つのインスタンスはどのようにオーバーラップしていますか(スコープ外のタイプを含む)

-- | Class that represents the relationship between a functor 'sup' containing 
-- a functor 'sub'. 
class (Functor sub, Functor sup) => sub :-<: sup where 
    inj :: sub a -> sup a 

-- | A functor contains itself. 
instance Functor f => f :-<: f where 
    inj = id 

-- | A functor is contained in the sum of that functor with another. 
instance (Functor f, Functor g) => f :-<: (Sum f g) where 
    inj = InL 

-- | If a functor 'f' is contained in a functor 'g', then f is contained in the 
-- sum of a third functor, say 'h', with 'g'. 
instance (Functor f, Functor g, Functor h, f :-<: g) => f :-<: (Sum h g) where 
    inj = InR . inj 

は今、次のデータ型を考えてみます。

type WeatherData = String 

data WeatherServiceF a = Fetch (WeatherData -> a) deriving (Functor) 

data StorageF a = Store WeatherData a deriving (Functor) 

、次のタイプ

FreeControl.Monad.Freeモジュールから来
fetch :: (WeatherServiceF :-<: g) => Free g WeatherData 

と機能。私はこの機能を使用しようと

は、その後、次のように:私は最初は有効なインスタンスがあることを理解し、

• Overlapping instances for WeatherServiceF 
          :-<: Sum WeatherServiceF StorageF 
    arising from a use of ‘fetch’ 
    Matching instances: 
    two instances involving out-of-scope types 
     instance (Functor f, Functor g) => f :-<: Sum f g 

     instance (Functor f, Functor g, Functor h, f :-<: g) => 
       f :-<: Sum h g 

を今すぐ:

reportWeather :: Free (Sum WeatherServiceF StorageF)() 
reportWeather = do 
    _ <- fetch 
    return() 

私が言って、重複・インスタンスのエラーを取得しますしかし、なぜ2番目が有効なインスタンスと考えられるのでしょうか?私は後者の場合には、変数をインスタンス化した場合、私はそれがWeatherServiceF :-<: StorageFというのは本当ではないので、インスタンスではありません

instance (Functor WeatherServiceF 
     , Functor StorageF 
     , Functor WeatherServiceF 
     , WeatherServiceF :-<: StorageF 
     ) => WeatherServiceF :-<: Sum WeatherServiceF g 

になるだろう。なぜGHCはそのような例を推測していますか?

は、私は、次のインスタンスが有効になっている:

{-# LANGUAGE DeriveFunctor   #-} 
{-# LANGUAGE FlexibleContexts  #-} 
{-# LANGUAGE FlexibleInstances  #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeOperators   #-} 

答えて

3

コンパイラは制約を見ずに、インスタンスの唯一の「頭」を考慮してインスタンスを選択できるようにしています。適用可能なインスタンスが選択されると、制約が検討されます。頭だけを見ている2つのインスタンスの間で判断できない場合は、重複します。

最終的な完全なプログラムで使用されるすべてのインスタンスがこのモジュールににインポートされる保証はありません。コンパイラが別のインスタンスの制約を満たすインスタンスを見ることができないことに基づいてインスタンスを選択することを決心した場合、異なるモジュールは、異なるタイプに基づいて、同じタイプに対してどの2つの重複するインスタンスを使用するかについて、各インスタンスで使用可能な一連のインスタンス。

オーバーラップチェックは、そのことを止めるためのものです。したがって、GHCがすべての制約を少なくともとして扱う唯一の方法は、与えられた状況でどのインスタンスが適用されるかを見ているときにが充足可能であるということです。それがちょうど1つの候補を残すとき、その候補は、他のインスタンスがプログラムのどこかで追加または削除されているかどうかにかかわらず残っています。次に、制約を満たすために、このモジュールで必要なインスタンスが使用可能であることを確認できます。

+0

私はそれについて知らなかった。私は、この質問の例でこの重複するインスタンスのエラーを回避できる理由はありますか? –

+0

もちろん、「OverlappingInstances」に頼らずに:) –

関連する問題