[英]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.