[英]Haskell types and typeclasses declaration
我試圖更好地理解 Haskell 中的類和實例。 因此,我正在研究:
http://learnyouahaskell.com/making-our-own-types-and-typeclasses
他們建議在這里嘗試:
instance (Eq m) => Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
但是當我這樣做時,我得到以下 output:
tryouts.hs:58:10: error:
Duplicate instance declarations:
instance Eq m => Eq (Maybe m) -- Defined at tryouts.hs:58:10
instance Eq a => Eq (Maybe a) -- Defined in `GHC.Maybe'
我怎樣才能克服這一點,go 實例化我自己的類型類聲明?
作者認為 class 前面的(Eq m) => Eq
對於限制實例的內容很重要。 這與定義Eq
時在 class 級別(例如)執行此操作明顯不同。 但是,我不確定我是否理解其中的區別。 這可能是我不明白 OOP 中類型類和常規 class 之間的區別以及前者的“繼承”性質的地方。
- 我怎樣才能克服這一點,go 實例化我自己的類型類聲明?
該錯誤表明在模塊中,它已經包含這樣的實例。 事實上,它在語義上是完全相同的,正如我們在源代碼中看到的那樣:
data Maybe a = Nothing | Just a deriving ( Eq -- ^ @since 2.01, Ord -- ^ @since 2.01 )
實現Eq
的默認方式是,如果兩項的數據構造函數相同,並且參數在元素方面相等,則返回True
。
您可以定義自己的類型,然后定義實例,例如:
data Maybe2 a = Nothing2 | Just2 a
instance Eq m => Eq (Maybe2 m) where
Just2 x == Just2 y = x == y
Nothing 2== Nothing2 = True
_ == _ = False
作者認為class前面的
(Eq m) => Eq
對於約束實例的內容很重要。 這與定義 Eq 時在 class 級別(例如)執行此操作明顯不同。 但是,我不確定我是否理解其中的區別。 這可能是我不明白 OOP 中類型類和常規 class 之間的區別以及前者的“繼承”性質的地方。
如果你會使用:
class Eq a => Eq (f a) where
...
那么這將意味着Eq (Maybe a)
將暗示Eq a
,所以情況正好相反。 然而這永遠不會起作用,因為如果Eq (Maybe Int)
是一個實例,那么Eq Int
是一個實例,但Eq Int
只能是一個實例,如果Int ~ fa
( Int
與fa
a
類型相同),並且是Eq
的一個實例。
您不能真正為Maybe a
“重新定義” Eq
,因為它已在 Prelude 中定義。 話雖如此,您可能有一種方法可以通過{-#LANGUAGE NoImplicitPrelude #-}
重新定義它,並仔細導入足夠的類型和類型類以避免導入包含Maybe a
的Eq
定義的文件,或者您可以使用其中一個編譯指示來允許重疊聲明,但我對此並不熟悉,所以不要相信我的話。
Eq m => Eq (Maybe m)
意味着為了讓Maybe m
成為Eq
類型 class 的實例, m
必須已經是Eq
的實例。 這是很自然的,因為為了比較Just a
和Just b
,您需要能夠比較a
和b
。 因此,您無法比較Just (+)
和Just (-)
之類的相等性。
您可以使用另一種方法來嘗試使用默認情況下從Prelude
導入的東西 - 使用hiding
。 在這種情況下,它可能如下所示:
import Prelude hiding (Maybe, Just, Nothing)
data Maybe a = Nothing | Just a
instance (Eq m) => Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.