2013-12-16 31 views
6

這是Inconsistent Eq and Ord instances?的後續問題。Haskell:標準庫假定Eq和Ord是兼容的嗎?

問題有本質上是:宣佈EqOrd實例的類型時,必須確保compare x y回報EQ當且僅當x == y回報True?創建破壞這個假設的實例是危險的嗎?這似乎是一個人們可以假設的自然法則,但似乎並沒有在前奏中明確說明,單子或函子法則。

基本的回答是:這樣做有點危險,因爲圖書館可能會認爲這個定律是成立的。

我的問題現在是:做任何標準庫(特別是SetMap)做出這個假設?只要我只依賴GHC提供的標準庫,選擇不兼容的類型EqOrd會危險嗎?(如果大問題仍然可以接受,我會問:哪些常用圖書館會採用此法律?)

編輯。我的用例與原始問題類似。我有一個自定義實例Eq,我用了很多。我想要Ord的唯一原因是我可以使用它作爲Map的域;我不關心具體的順序,也不會在代碼中明確地使用它。所以如果我可以使用Ord的派生實例,那麼我的生活將會更容易,我的代碼更清晰。

+5

「,這通常用過的圖書館承擔這個法則「---人的大腦? –

+0

事實上,一個更好的問題是,對於一個(未調整的)例子,其中'(a == b)/ =(比較b == EQ)'是有意義的。 – Ingo

+1

這只是閒暇的好奇心,還是你有一個用例記住你認爲有意義讓兩者有所不同?如果是後者,我很樂意看到它出現(嚴重的是,我現在很好奇,並且自己也想不到一個好的用例......) – jamshidh

回答

6

standard prelude中的Ord自身定義需要有已經是一個Eq實例:

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

因此,這將是一樣錯違反

x == y   = compare x y == EQ 
    x /= y   = compare x y /= 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實例,則Ordcompare將用於結果Map的其他功能,這是Eq==Ord相同的假設的compare和測試EQ

作爲圖書館程序員,如果任何特殊目的運營商爲特定目的跑贏compare,我不會感到驚訝。畢竟,這就是爲什麼它們是EqOrd類的一部分,而不是被定義爲所有EqOrd實例的多態。即使compare更方便,我也可以重點使用它們。如果我做了,我可能會定義是這樣的:

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

爲了延長Cirdec的回答,類型類實例應該時才作出所定義的操作是某種規範。如果有一個合理的Eq沒有擴展到合理的Ord,那麼最好的做法是選擇另一個Eq或不定義Ord。爲「其他」平等創建一個非多態函數是很容易的。

該張力的一個很好的例子是潛在Monoid實例

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

,其與其他的「明顯的」 Monoid實例

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

競賽在這種情況下所選擇的路徑是實例化既不因爲目前尚不清楚其中一個是「規範」的。這通常最符合用戶的期望並防止錯誤。

1

我已經通過這個和你原來的問題讀,所以我會滿足您的一般問題....

你想這個 -

Map BigThing OtherType 

和這個 -

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

出於性能原因,其中一種情況必須是確切的,另一種情況應該忽略其中的一些數據。 (它是(==)在第一個問題中需要精確,但是看起來你可能會在這個問題中解決相反的問題。

例如,你想要的地圖只存儲結果基於一些標籤,就像一個

`name::BigThing->String` 

但(==)應做一次深層比較。一種方法是定義不兼容的compare(==)函數。不過......在這種情況下,這是不必要的。爲什麼不改用地圖

Map String OtherThing 

和不喜歡這個 -

lookup (name obj) theMap 

這是非常罕見的指數直接在非常大的文檔數據的查詢....

+0

只是爲了記錄,老問題實際上是從其他人,而不是我(也許我的措辭有點不清楚) - 但我的情況已經足夠接近,這個答案也適用於我,所以無論如何謝謝。 – PLL