2016-04-21 86 views
1

我需要使用這個數據結構data D = C Int Float,我需要將它與Int進行比較,例如a::D == 2不同類型的Haskell Eq

如何創建一個實例來定義這種Eq?

謝謝!

+0

請注意,因爲我不認爲你會收到關於此事的通知:我編輯了我的答案以添加更好的解決方案。 –

回答

4

你不能; ==有簽名a -> a -> Bool,所以它不能像這樣使用。

使用convertible包,你可以定義

(~==) :: (Convertible a b, Eq b) => a -> b -> Bool 
x ~== y = case safeConvert x of 
      Right x' -> x' == y 
      Left _ -> False 

(==~) :: (Convertible b a, Eq a) => a -> b -> Bool 
(==~) = flip (~==) 

instance Convertible Int D where ... 
-- or D Int depending on what you have in mind 

,而不依賴於convertible,你可以只定義轉換功能無論是從IntD(寫a == fromInt 2),反之亦然。

一個不太推薦的路線(對於這個具體情況,我認爲它比第一個解決方案簡單得多)將是定義你自己的類型類,例如,

class Eq' a b where 
    (=~=) :: a -> b -> Bool 

instance Eq a => Eq' a a where 
    x =~= y = x == y 

instance Eq' D Int where ... 

+4

我不認爲創建自定義類是一個很好的建議。尤其是對新人來說。 –

+0

@NikitaVolkov我已經有了一個「更合理」的選擇,但我已經改寫了答案,以添加一個更好的(IMO)解決方案,並把它放在最後。 –

7

我會實現一個投影:

getInt :: D -> Int 
getInt (C i _) = i 

,然後用它比較:

getInt myD == 5 

你甚至可以包括到創紀錄的:

data D = C { getInt :: Int, getFloat :: Float } 

如果你喜歡

1

可以做,但我懷疑你會想這樣做。正如阿列克謝提到(==)的類型是Eq a=>a->a->Bool,所以做這項工作的唯一方法就是讓2的類型爲D。最初,這可能看似荒謬,但實際上可製成數字有你想要的任何類型,只要該類型是Num

instance Num D where 
    fromInteger x = C x 1.0 

的實例還有很多事情需要解決,但.. ..

首先,你需要充分執行Num的所有功能,包括(+)(*)abssignumfromInteger(negate | (-))

呃!

其次,你有那額外的Float來填寫fromInteger。我選擇了上面的值1.0,但那是任意的。

三,您還需要實際製作D一個Eq的實例,以填寫實際的(==)

instance Eq D where 
    (C x _) == (C y _) = x == y 

注意,這也是很隨意的,因爲我需要忽略浮動值,以獲得(==)做你希望它是什麼。

底線是,這會做你想要做什麼,但在濫用Num型的成本,以及Eq型相當嚴重....的Num型應保留的東西,你居然會考慮爲一個數字,並且Eq類型應該保留用於比較兩個完整的對象,每個部分都包括在內。