[英]What does deriving do/mean in Haskell?
堆棧溢出推導的定義是:
“在 Haskell 中,派生實例是與數據或新類型聲明一起自動生成的實例聲明。派生實例聲明的主體在語法上是從關聯類型的定義中派生的。”
老實說,我真的不明白其中的任何一個。
以下代碼摘自:鏈接
data BaseballPlayer = Pitcher
| Catcher
| Infielder
| Outfielder
deriving Show
barryBonds :: BaseballPlayer -> Bool
barryBonds Outfielder = True
barryInOf = print(barryBonds Outfielder)
我的問題是,派生語句在這種特定情況下做什么,以及派生語句一般做什么?
簡而言之:
deriving
自動實現一些 Haskell 類型類的函數,例如Show
和Eq
。 這不能用任意類型類來完成,但deriving
工作的類型類對於自動實現來說足夠簡單。
Show
類型類定義了如何將數據類型表示為String
函數。
更廣泛:
你熟悉類型類嗎?
https://www.haskell.org/tutorial/classes.html
類型類類似於 Java 中的接口:它們定義了一些函數,任何想要使用這些函數的數據類型都可以實現這些函數。
例如,假設我們有一個這樣的類:
class Comparable a where
lessThan :: a -> a -> Bool
equalsTo :: a -> a -> Bool
當心字的class
。 它意味着 Haskell 設置中的類型類,而不是您在面向對象語言中聽到的典型“類”。 這里的a
是一種填充類型,類似於您期望模板在 C++ 中的工作方式和泛型在 Java 中的行為方式。
假設我們定義了一個數據類型如下:
data Color = Red | Green | Blue
為了使Comparable
與Color
工作,我們實現了一個Comparable
instance
:
instance Comparable Color where
lessThan Red Green = True
lessThan Red Blue = True
lessThan Green Blue = True
lessThan _ _ = False
equalsTo Red Red = True
equalsTo Green Green = True
equalsTo Blue Blue = True
equalsTo _ _ = False
粗略地說,這現在允許您相互“比較” Red
、 Green
和Blue
。 但是有沒有辦法讓 GHC 自動猜測這是您想要的確切“順序”?
退后一步,類型類Show
具有類似的結構:
https://hackage.haskell.org/package/base-4.9.1.0/docs/src/GHC.Show.html#Show
class Show a where
showsPrec :: Int -> a -> ShowS
show :: a -> String
showList :: [a] -> ShowS
showsPrec _ x s = show x ++ s
show x = shows x ""
showList ls s = showList__ shows ls s
需要注意的是,類型類中的函數可以相互定義。 事實上,我們也可以很容易地做到:
class Comparable a where
lessThan :: a -> a -> Bool
equalsTo :: a -> a -> Bool
greaterThan :: a -> a -> Bool
greaterThan lhs rhs = not (lessThan lhs rhs && equalsTo lhs rhs)
然而,關鍵在於:對於任意用戶定義的類型類,當您嘗試將類型類與諸如Color
或BaseballPlayer
之類的數據類型相關聯時,GHC 不知道它們的功能應該如何實現。 對於某些類型類,例如Show
、 Eq
、 Ord
等,其功能足夠簡單,GHC 可以生成默認實現,您當然可以自己覆蓋這些實現。
事實上,讓我們嘗試編譯以下內容:
data Color = Red | Green | Blue deriving (Comparable)
我得到的結果是這樣的:
test.hs:9:43:
Can't make a derived instance of ‘Comparable Color’:
‘Comparable’ is not a derivable class
Try enabling DeriveAnyClass
In the data declaration for ‘Color’
當然,一些GHC擴展可以用來擴展的電源deriving
,但這是另一天:)
在這種特定情況下,它會為您的類型生成一個Show
實例,如下所示:
instance Show BaseballPlayer where
show Pitcher = "Pitcher"
show Catcher = "Catcher"
show Infielder = "Infielder"
show Outfielder = "Outfielder"
通過這種方式, BaseballPlayer
類型的值可以轉換為字符串,例如通過print
。
選擇字符串,使其成為有效的 Haskell 表達式,一旦求值,就可以重建原始值。
一般情況有點復雜,但遵循相同的想法:將值轉換為 Haskell 表達式字符串。 例如
data T = T Int (Maybe Bool) deriving Show
將制作實例,以便
show (T 1 Nothing) = "T 1 Nothing"
show (T 2 (Just 3)) = "T 2 (Just 3)"
注意在最后一種情況下括號也是如何生成的。 這是使用showsPrec
類成員完成的,但這並不重要。
派生意味着您的數據類型能夠自動“派生”某些類型類的實例。 在這種情況下BaseballPlayer
派生Show
這意味着我們可以使用任何需要Show
實例來與BaseballPlayer
一起工作的函數。
自動派生使您更容易避免樣板。 最常見的自動派生類型類是Show
和Eq
,因為編譯器可以為這些類型類生成非常合理的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.