3

MultiParamTypeClassesと一緒にFunctionalDependencies-ExtensionofHaskellで遊んでいました。私は次のように定義しました。

class Add a b c | a b -> c where
    (~+) :: a -> b -> c
    (~-) :: a -> b -> c
    neg :: a -> a
    zero :: a

これは正常に機能します(明示的な変換なしでIntとDoubleを追加できるようにするという最終的な目標を持って、IntとDoubleのインスタンスを試しました)。

negまたは(〜-)のデフォルトの実装を次のように定義しようとすると:

class Add ...
    ...
    neg n = zero ~- n

GHCi(7.0.4)は私に次のように言っています:

Ambiguous type variables `a0', `b0', `c0' in the constraint:
  (Add a0 b0 c0) arising from a use of `zero'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `(~-)', namely `zero'
In the expression: zero ~- n
In an equation for `neg': neg n = zero ~- n

Ambiguous type variable `a0' in the constraint:
  (Add a0 a a) arising from a use of `~-'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: zero ~- n
In an equation for `neg': neg n = zero ~- n

私はここで問題を理解していると思います。GHCは、どのゼロを使用するかを知りません。これは、ゼロである可能性があり、それが、正しい引数を持ち、を生成する~-ことを知っているだけのに供給されるためです。aa

では、まったく同じインスタンスからゼロにするように指定するにはどうすればよいですか。つまり、次のように表現するにはどうすればよいでしょうか。

neg n = (zero :: Add a b c) ~- n

とは、周囲のクラスのabcではなく、abとcであると思います。aでは、ローカル型変数への参照である型をどのように表現できますか?bc

4

2 に答える 2

6

1つのタイプのみを使用するスーパークラスに引き出しnegます。zero

class Zero a where
    neg :: a -> a
    zero :: a

class Zero a => Add a b c | a b -> c where
    (~+) :: a -> b -> c
    (~-) :: a -> b -> c

重要なのは、あなたのやり方zero :: Intzerofrom Add Int Int Intまたはzerofromであり、Add Int Double Doubleデフォルトの実装、インスタンス宣言、または通常のコードの内部から参照しているかどうかに関係なく、2つの間で曖昧さを解消する方法はないということです。

zerofromAdd Int Int IntzerofromAdd Int Double Doubleが同じ値になることに反対するかもしれませんが、コンパイラーは、誰かがAdd Int Char Bool別のモジュールで定義してzero別の値を指定しないことを知ることができません。)

型クラスを2つに分割することで、あいまいさを取り除きます。

于 2012-05-04T11:52:52.593 に答える
3

zero関数をAddクラスの一部として表現することはできません。クラス宣言のすべての型変数は、クラスの各関数の型宣言で検出される必要があります。そうしないと、制約が少なすぎるため、Haskellは使用するタイプインスタンスを決定できません。

つまり、zeroはモデリングしているクラスのプロパティではありません。あなたは基本的に次のように言っています:「任意の3つのタイプ、、、aの場合b、タイプにcはゼロ値が存在する必要がありますa」、これは意味がありません。いずれかを選択するbc、問題が解決するため、b完全cに使用できなくなります。したがって、Add Int Int Intまたはを持っている場合Add Int (Maybe String) Boat、Haskellはどちらのインスタンスを優先するかを知りません。否定と「ゼロネス」のプロパティを、次のタイプの個別のクラスに分離する必要があります。

class Invertible a where
  invert :: a -> a

neg :: Invertible a => a -> a
neg = invert

class Zero a where
  zero :: a

class Add a b c | a b -> c where
  (~+) :: a -> b -> c
  (~-) :: a -> b -> c

なぜあなたが;のInvertibleZero制約さえ必要になるのか分かりません。Addゼロの値を知らなくても、いつでも数値を追加できますね。negの要件として表現する理由~+; 否定できない数を追加できるはずの数がありますか(たとえば、自然数)?クラスの懸念事項は別にしてください。

于 2012-05-04T11:56:23.097 に答える