派生堆栈溢出的定义是:
“在Haskell中,派生实例是一个实例声明 与数据或新类型一起自动生成 宣言。派生实例声明的主体 语法上来自相关类型的定义。“
说实话,我真的不明白。
以下代码取自:Link
data BaseballPlayer = Pitcher
| Catcher
| Infielder
| Outfielder
deriving Show
barryBonds :: BaseballPlayer -> Bool
barryBonds Outfielder = True
barryInOf = print(barryBonds Outfielder)
我的问题是,在这个特定情况下,派生语句做了什么, 以及派生声明一般来说做什么?。
这个问题不是重复的: how does deriving work in haskell OBS:我不是问它的源代码如何工作,我问它是做什么的。
答案 0 :(得分:5)
在这种特定情况下,它会为您的类型生成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
类成员完成的,但它并不重要。
答案 1 :(得分:5)
简而言之:
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
一致,我们实施了instance
Comparable
:
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
或{{1}等数据类型相关联时,GHC不知道应如何实现它们的函数}}。对于某些类型类,例如BaseballPlayer
,Show
,Eq
等,功能很简单,GHC可以生成默认实现,您当然可以覆盖它们自己。
事实上,让我们尝试编译以下内容进行实验:
Ord
我得到的结果是:
data Color = Red | Green | Blue deriving (Comparable)
当然,可以使用一些GHC扩展来扩展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’
的功能,但这会延长一天:)
答案 2 :(得分:3)
派生意味着您的数据类型可以自动导出"派生"某些类型类的实例。在这种情况下,BaseballPlayer
派生Show
,这意味着我们可以使用任何需要Show
实例的函数来处理BaseballPlayer
。
自动派生使您更容易避免样板。自动派生的最常见类型类是Show
和Eq
,因为编译器可以为这些类型类生成非常合理的值。