23

したがって、一緒によく使用する型クラスのペアがあり、毎回両方を指定することは避けたいと考えています。基本的に、置く代わりに

:: (Ord a, Fractional a, Ord b, Fractional b, ... Ord z, Fractional z) =>

すべての型指定の最初に、

:: (OrdFractional a, OrdFractional b, ... OrdFractional z)

したがって、これを行う方法に関する私の最初のアイデアは、新しい型クラスを宣言することでした

module Example where

class (Fractional a, Ord a) => OrdFractional a

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)

しかし、これは私が望んでいたほど自動的には機能しませんでした:

% ghci
Prelude> :l Example.hs
Ok, modules loaded: Example.
Prelude Example> example (1::Float,3::Float) (2,2) (3,1)

<interactive>:1:0:
    No instance for (OrdFractional Float)
      arising from a use of `example' at <interactive>:1:0-39
    Possible fix:
      add an instance declaration for (OrdFractional Float)
    In the expression: example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
    In the definition of `it':
        it = example (1 :: Float, 3 :: Float) (2, 2) (3, 1)

インスタンスを手動で作成するのは面倒に思えるので、次に、インスタンスを自動的に作成しようと考えました。

module Example where

class OrdFractional a
instance (Fractional a, Ord a) => OrdFractional a

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)

しかし、コンパイラはそれを好まなかった:

ghc -c Example.hs

Example.hs:4:0:
    Illegal instance declaration for `OrdFractional a'
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are type *variables*,
         and each type variable appears at most once in the instance head.
         Use -XFlexibleInstances if you want to disable this.)
    In the instance declaration for `OrdFractional a'

これを行う方法はありますか?

4

4 に答える 4

33

GHC 7.4で導入されたConstraintKinds拡張機能により、制約は種類の型にConstraintなりました。そのため、通常の型の同義語を使用して、必要なものを取得できます。

{-# LANGUAGE ConstraintKinds #-}

type OrdFractional a = (Ord a, Fractional a)
于 2012-11-29T07:42:01.803 に答える
11

必要なのはクラスエイリアスです。http://repetae.net/recent/out/classalias.htmlでHaskellに追加する提案があります

于 2008-11-20T22:02:00.977 に答える
10

コンパイラが「Use -XFlexibleInstances」と言ったら、追加してみてください

{-# LANGUAGE FlexibleInstances #-}

ソースの一番上に移動します(もちろん、ドキュメントを読んで、それが何をするのかを学びましょう!)。

この特定のケースでは、これによりコードが機能します。

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

インスタンスヘッドでコンテキストを有効にするには、柔軟なインスタンスが必要です。コンパイラは、コンテキストを処理するときに、コンテキストへの追加とコンテキストへの追加を終了できる=>ため、決定不可能なインスタンスが必要です。これは、最終的な決定に直接役立ちません。適切に恐ろしい状況では、タイプチェックは分岐する可能性があります。コンパイラは本当にそれを好きではありません。(コンパイラが永久に動作し続けたり、メモリが不足したりした場合は、おそらく気に入らないでしょう。)OrdFractional aFractional aOrd aa

于 2009-07-03T05:44:47.360 に答える
3

いいえ。

他のクラスを意味するスーパークラスのソリューションは、Haskell で可能な、あなたが望むものに最も近いものです。それにはその新しいクラスの手動インスタンスが必要ですが、たとえば書き換えライブラリで使用されることもあります。

CesarB が述べたように、クラス エイリアスはあなたが望むこと (およびそれ以上) を行いますが、おそらくそれには多くの問題があるため、おそらく何年も前から存在し、実装されていない提案にすぎません。代わりに、他のさまざまな提案が飛び出しましたが、それらのどれも実装されませんでした. (これらの提案のリストについては、このHaskellwiki ページを参照してください。) Hac5 でのプロジェクトの 1 つは、 GHC を変更して、コンテキスト シノニムと呼ばれるクラス エイリアスの小さなサブセットを含めることでした(これは、ここで求めていることを正確に実行し、それ以上のことはしません)。 、しかし悲しいことに、それは決して完成しませんでした。

于 2009-07-03T07:41:38.947 に答える