2013-12-16 6 views
6

これはInconsistent Eq and Ord instances?へのフォローアップの質問です。Haskell:標準ライブラリはEqとOrdが互換性があると仮定しますか?

質問は基本的にあります:タイプにEqOrdインスタンスを宣言するとき、人はそのcompare x y戻りEQを保証しなければならない場合にのみx == y戻りTrue場合は?この仮定を破るインスタンスを作成するのは危険ですか?それは自然法則のように思えるかもしれませんが、それはPreludeに明示されていないようです。モナドまたはファンクターの法則。

基本的な対応は、ライブラリがこの法律が成立すると仮定できるので、これを行うのは少し危険です。

私の質問は今です:標準ライブラリのいずれか(特にSetまたはMap)はこの前提をしていますか? GHCで提供されている標準ライブラリのみに依存している限り、互換性のない型を持つことは危険ですか?EqOrd(大量の質問が依然として受け入れられた場合は、一般的に使用されているライブラリのどれがこの法律を前提としていますか?)

編集します。私のユースケースは元の質問と似ています。私はEqのカスタムインスタンスを持つ型を持っています。これはかなり使います。私がOrdを望む唯一の理由は、私がMapのドメインとして使用できるようにするためです。私は特定の順序を気にせず、コードで明示的に使用することはありません。したがって、Ordの派生インスタンスを使用することができれば、私の人生は楽になり、コードはより明確になります。 (

class (Eq a) => Ord a where 
    ... 

それは違反するだろうように、

x == y   = compare x y == EQ 
    x /= y   = compare x y /= EQ 

に違反し、同じように間違って次のようになります。

+5

を「と一般的に使用された図書館はこの法律を "---人の頭脳? –

+0

確かに、 '(a == b)/ =(a b == EQと比較する)'が意味をなさない、(非contrieved)例の方がよいでしょう。 – Ingo

+1

これはちょうどアイドルな好奇心ですか、または2つの違いを作るのが理にかなっていると思われるユースケースがありますか?後者の場合、私はそれを見たいと思っています(真剣に、私は今興味があり、良いユースケースを自分で考えることはできません....) – jamshidh

答えて

6

standard preludeOrd自体の定義がすでにEqインスタンスが存在することが必要ですOrdのこれらの演算子のデフォルト定義から)。

x <= y   = compare x y /= GT 
    x < y   = compare x y == LT 
    x >= y   = compare x y /= LT 
    x > y   = compare x y == GT 

編集:使用ライブラリ

での標準ライブラリはOrd==/=演算子の使用をしなかった場合、私は非常に驚くだろう。特定の目的演算子(==/=<=<>=>)が頻繁にcompareよりも便利なので、私は彼らがmap秒またはfilter秒間コードで使用される参照を期待したいです。

see == being used in guards on keys in Data.Map in fromAscListWithKeyです。この特定の関数は、Eqクラスのみを呼び出しますが、そのキーがOrdのインスタンスでもある場合は、Mapの他の関数にはOrdのがあります。の==Ordと同じです'compareEQのテスト。

ライブラリプログラマとして、特殊目的の演算子のいずれかが特定の目的のためにcompareを上回ると驚くことはありません。結局のところ、それらはEqまたはOrdインスタンスの多型として定義されるのではなく、EqクラスとOrdクラスの一部です。 compareがより便利な場合でも、私はそれらの使用のポイントを作るかもしれません。私がやった場合、私はおそらくのようなものを定義したい:Cirdecの答えを拡張するには

compareOp :: (Ord a) => Ordering -> Bool -> a -> a -> Bool 
compareOp EQ True = (==) 
compareOp EQ False = (/=) 
compareOp LT True = (<) 
compareOp LT False = (>=) 
compareOp GT True = (>) 
compareOp GT False = (<=) 
3

を定義されている操作が何とか正規のであれば、型クラスのインスタンスにのみ行われるべきです。合理的なOrdに達しない妥当なEqがある場合は、Eqを選択するか、Ordを定義しないことをお勧めします。 "他の"等価の非多形関数を作成するのは簡単です。他の「明白な」Monoidインスタンスで争っ

この張力の良い例は、潜在的Monoidインスタンス

instance Monoid Int where 
    mzero = 0 
    mappend = (+) 

instance Monoid Int where 
    mzero = 1 
    mappend = (*) 

この場合、選択されたパスは、いずれも理由をインスタンス化することでしたあるものが他のものよりも "標準的"であることは明らかではありません。これは通常、ユーザーの期待に最も適合し、バグを防止します。

1

私はこれとあなたの元の質問を読んできたので、私はあなたの一般的な問題に対処します....

あなたがthis-

Map BigThing OtherType 

とthis-

(==)::BigThing->BigThing->Bool 
たい

これらのケースの1つは正確でなければならず、パフォーマンス上の理由から、データの一部を無視する必要があります。 (それは(==)最初の質問では正確である必要があったが、あなたはこの質問で逆に取り組んでいるように思えます....どちらの方法でも同じ答え)。

たとえば、あなただけの

`name::BigThing->String` 

けど(==)のように、いくつかのラベルに基づいて結果を格納するマップを望んで比較深いを行う必要があります。これを行う1つの方法は、互換性のないcompare(==)関数を定義することです。但し....

この場合、これは不要です。なぜないだけではなく、マップ

Map String OtherThing 

を使用し、それが直接、非常に大規模な文書データのインデックスにはかなり稀であるthis-

lookup (name obj) theMap 

のような検索を行う....

+0

レコードのためだけに、古い質問は実際には誰か他の人からではなく(おそらく私の言葉は少し不明でした) - しかし、私の状況は近いので、この答えが私のために働くので、どうかありがとうございます。 – PLL

関連する問題