8

Foo関数を所有するというクラスがありますgen :: Int -> [Foo]Fooたとえば、その方法でインスタンスを作成できます。

data FooTest = FooTest Int

instance Foo FooTest where
  gen n = replicate n (FooTest 0)

Barここで、関数を定義するという別のクラスがあると想像してみましょうbar :: Bar -> IO ()。の各インスタンスはのインスタンスでFooある必要があります、実装は各インスタンスでまったく同じです。次に例を示します。BarBar

class Foo f where
  gen :: Int -> [f]

class Bar b where
  bar :: b -> IO ()

instance Bar Foo where -- obviously that doesn’t work
  bar _ = putStrLn "bar through any Foo instance"

instance (Foo f) => Bar f where -- this needs the FlexibleInstance GHC extension first, then it still throws shit saying that the constraint is not smaller that I don’t shit
  bar _ = putStrLn "bar through any Foo instance"

ここでの問題は、最初のクラスのインスタンスが他のクラスをインスタンス化するために同じ実装を共有するという事実に言及するために、クラスを別のインスタンスにする方法を見つけることができないことです。

何か案が?

前もって感謝します。

4

1 に答える 1

4

の2つの拡張子を使用して、最後のインスタンスを使用して、必要なことを正確に実行できます。FlexibleInstancesUndecidableInstances

名前が示すように、2番目の拡張機能を使用すると、終了しないインスタンスを作成できる可能性があります。これにより、コンパイル時に無限ループが発生する可能性があります。ただし、実装は特定の再帰深度で任意に制限されるため、実際にはコンパイル時間が無限になることはありません。

拡張機能なしでこれを行う方法はまったくわかりません。ただし、将来的に他のコンパイラを使用する可能性がない限り、拡張機能の使用は本質的に悪いことではありません。

また、ランダムなスタイルの注意:制約が1つしかない場合、括弧はオプションです。したがって、次のように書くことができます。

instance Foo f => Bar f where ...

これはそれほど重要ではありませんが、2番目のバージョンの方が見栄えが良いと思います。

于 2013-03-05T09:33:08.663 に答える