2016-11-04 7 views
2

次のコードdoesntのコンパイル:Haskellのクラスの依存関係

class Foo f where 
    getInt :: f -> Int 

class Bar b where 
    getFooFromBar :: Foo f => b -> f 

someFunction :: Bar b => b -> Int 
someFunction bar = getInt $ getFooFromBar bar 

エラーがCould not deduce (Foo f) arising from a use of 'getInt' from the context (Bar b)

である私は、次のように私はBarのクラスを変更することでエラーを修正することができます知っている:

class Foo f => Bar f b where 
    getFooFromBar :: b -> f 

しかし、私がしなかった場合は、のすべてのインスタンス署名にfを追加する必要があります。

Foo fの制約は、クラス全体ではなく、getFooFromBarのシグネチャだけにすることでこれを行う方法はありますか?

+2

私はあなたがgetFooFromBar' 'のタイプを再考をお勧めします - それは'あいまいなために態勢を整えて見えます型変数 'エラー。 – Alec

+1

@Alec完全なエラーは実際には '型変数 'f0'があいまいです。 – duplode

+0

[Haskell Type-Ambiguityのケースを理解する]の可能な複製(http://stackoverflow.com/questions/21220655/understanding-a-case-of-haskell-type-ambiguity) – Cactus

答えて

4

しかし、もし私がfをすべてのインスタンス署名Barに追加しなければならないのが好きです。

技術的に言えば、あなたのサンプルをコンパイルするために、技術的に言えば、それを行う必要はありません。型の注釈を使用してFooのインスタンスをsomeFunctionに指定し、あいまいな型の変数エラーを解決できます。しかし、より深刻な問題があります。

class Foo f where 
    getInt :: f -> Int 

class Bar b where 
    getFooFromBar :: Foo f => b -> f 

つまり、すべての実用的な目的では不可能です。 getFooFromBarのタイプは、タイプfの結果を生成するのにそれを使用することができ、Fooのインスタンスを持つと言います。しかし、どのようにfのためにこの値を具体化しますか? getFooFromBarを定義するときに特定のインスタンスに達するのは役に立ちません。それはCouldn't match type ‘f’ with ‘Blah’タイプのエラーです。その直接的な解決策は、別の理由から、FooのインスタンスをBarインスタンスで使用するように指定することです。あなたはそれがよりよいというマルチパラメータ型クラスよりも、タイプの家族と一緒に行うことを見つけるかもしれない:

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE FlexibleContexts #-} 

class Foo f where 
    getInt :: f -> Int 

class Foo (FooBar b) => Bar b where 
    type FooBar b :: * 
    getFooFromBar :: b -> FooBar b 

instance Foo Char where 
    getInt = const 99 

instance Bar Char where 
    type FooBar Char = Char 
    getFooFromBar = const 'a' 

someFunction :: Bar b => b -> Int 
someFunction = getInt . getFooFromBar 
GHCi> someFunction 'z' 
99 
関連する問題