2012-03-03 9 views
6

私は、誘導的にクラスインスタンスのペアを定義しようとしています。つまり、Haskell "not"型制約

class Foo a b | a -> b where 
    foo :: a -> b 

instance (not?)Foo a => Bar a b 
    foo x = ... 

instance Foo a => Bar a b 
    foo x = ... 

最初のインスタンスは基本アクションを決定し、秒は再帰的にfooを呼び出します。これを行う方法はありますか?良い例は、リストを平坦化することです。最初のケースではそれがアイデンティティ関数であり、2番目のケースではコンカットの再帰的アプリケーションです。

+10

ハスケルでは、与えられた型が与えられた型クラスのインスタンスではないことを確かめることは不可能です。他の人がインスタンスを提供する独自のコードでコードをコンパイルできるからです。 –

答えて

5

ここには、任意のレベルのネストされたリストで動作するimplementation of a flatten functionがあります。私は本当にそれを使用することをお勧めしません - ここではちょうどhaskellのような何かを達成するためのデモンストレーションのために。

+5

IncoherentInstancesを使用することは問題の招待です。 – augustss

+1

@augustss、非常に真実なので、私がトップに置いた話し手。私は 'IncoherentInstances'を使わずに' flatten'を実装することは可能だとは思っていません(これはおそらく、この関数に依存するプログラムを設計することは悪い考えです)。 –

+1

@ is7s:そこにある解決法は、フラット化されたリストの型を派生させることはできません(flatten [3]、[4]] :: [Int] 'として指定する必要があります。 –

8

非常に簡単な理由から、この選択を直接行う方法はありません。インスタンス選択では、「ヘッド」、つまり=>の後ろの部分のみが表示されます。コンテキスト内に置かれたもの - =>の前の部分 - は、選択されたインスタンスに影響を与えることができます。

単純なケースでは、「基本ケース」の種類が限られているなど、問題を完全に回避することができます。一般的な例としては、タイプレベルのリストがあります。ここでは、Consの再帰的ケースと、Nilのベースケースがあります。

一般的には、ある条件が満たされているかどうかに基づいてタイプを選択し、実際の実装を「ヘルパー」クラスに渡す「条件付きテスト」タイプのクラスが必要です。条件付きの結果値をパラメータとして使用し、インスタンスを選択します。

+1

一般的なリストをフラットにしてクラスメンバーを実装する方法は? – Jonathan

+7

さて、最も正直な答えは、私がしないことです。多様な入力を壊すことなくそれを行う方法はありません。そして、私の意見では、面倒を正当化するのに十分ではありません。つまり、リストを平坦化するために、重複するインスタンスに頼って、再帰的なケースと基本的なケースのどちらかを選択することができると思います。ここで 'OverlappingInstances'を使用していますか?あなたはおそらくそれを必要とするでしょう。 –

+3

なぜジェネリックリストのフラット化機能が必要ですか?まれに有用です。 – augustss