2017-11-08 18 views
9

固定します。代わりに、GHCはそれがFoo a => SomeClass aインスタンスを使用して、そうしなければならない前提としていますは、このコードを検討型エラー

Foo.hs:16:17: 
    Could not deduce (Foo a) arising from a use of ‘bar’ 
    from the context (SomeClass a) 
     bound by the type signature for foo :: SomeClass a => a -> Int 
     at Foo.hs:15:8-32 
    Possible fix: 
     add (Foo a) to the context of 
     the inferred type of x :: Int 
     or the type signature for foo :: SomeClass a => a -> Int 
    In the expression: bar t 
    In an equation for ‘x’: x = bar t 
    In the expression: let x = bar t in x 

この修正する2つの方法があります。foo

  1. が私にラインinstance SomeClass Intを追加はlet x = bar t in x
  2. bar tにを変更し、プログラム

ここでは何が起こっていますか?なぜこの問題が発生しているのですか?これらの修正はなぜ機能しますか?


この例は、私の実際の問題によって単純化されています。多言語変換のためのCubixフレームワーク(arxiv.org/pdf/1707.04600)での作業中にこの問題が発生しました。

私の実際の問題には、制約InjF f IdentL FunctionExpL( "fは、関数呼び出しで関数を表すために識別子が使用される言語です"という関数)が含まれています。私は(オーバーラップ可能な)インスタンス(FunctionIdent :<: f) => InjF f IdentL FunctionExpLを持っています。これは、型チェッカーが握っているので、私に偽のCould not deduce FunctionIdent :<: fエラーを与えます。

特定のFooの範囲にインスタンスInjF Foo IdentL FunctionExpLが存在する場合でも、このエラーは解決されます。したがって、解決策は完全なストーリーではないことが予測されるleftaroundaboutの答えです。

+2

'{ - #OVERLAPPABLE# - }'と '{ - #LANGUAGE FlexibleContexts# - } 'は何にも影響しません。コンパイルの別の方法: 'x :: Int'を' let'バインディングに追加してください。 – Alec

+1

恐らく、最も厄介なことは、モジュール内に_インスタンスがあるときにタイプチェックすることです... – leftaroundabout

答えて

3

この理由は、コンパイラは可能な限り一般的なようxを作るしようとしていることである:それは(SomeClass a) => Intになりたいと思っている(あなた自身それを書いた場合は、あいまいな形になり、これを注意してください)。この種の奇妙なローカルタイプを防ぐ1つの方法は、-XMonoLocalBindsを有効にすることですが、実際には推奨しません。

ここで、コンパイラは型チェックを行います。その時点で、範囲内にちょうどinstance SomeClassがあります。キャッチオール(Foo a) => SomeClass aなので、あいまいさはありません。 (原則として、Haskellはインスタンスの解決においてあいまいさを完全に禁じています; OVERLAPPABLEはこれを覆してしまいますが、実際には必要なときにアクションにジャンプします。たとえば、instance SomeClass Intがあるときのように)。タイプチェックはcです。これは、実際にクラス制約をインスタンスの制約に置き換えたい場合に必要です。これは、与えられた例では役に立たないように見えるかもしれないが、あなたはそのがスーパークラスとして表現できないできるため、はるかに合理的なあなたのコードよりもフォーム

instance Bar a => SomeClass (Maybe a) 

...のインスタンスを持っている場合、それは実際には非常に重要です重なり合うことなく完全にOKです。コンパイラがこれらの状況でBar aに解決された制約を減らさなかった場合、実際にMaybeタイプを解決することはできませんでした。

結論:重複するインスタンスを避ける。可能であればスーパークラス宣言によるクラス関係を表現し、そうでない場合は制約をGADTに反映させます(どちらの制約が使用されるか厳密に制御できます)。

+0

1)範囲内の唯一のインスタンスは何ですか(Foo a => SomeClass a)?宣言の(SomeClass a)制約はどうでしょうか? –

+0

2)単純化するためにSomeClass(Maybe a)制約を直ちに単純化する必要があるのはなぜですか?宣言する文脈をすでに見てから、その決議の段階を最後まで遅らせることができないのはなぜですか? –

+0

3)これは私が与えた簡略化された例を説明するのに役立ちますが、実際の例では不足しています。実際の例を与えるために投稿を編集します。 –

関連する問題