什么在Haskell中派生/做什么?

时间:2017-06-25 09:12:04

标签: haskell functional-programming deriving

派生堆栈溢出的定义是:

  

“在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:我不是问它的源代码如何工作,我问它是做什么的。

3 个答案:

答案 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的类型类(例如ShowEq)实现函数。使用任意类型类无法完成此操作,但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

要使ComparableColor一致,我们实施了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

粗略地说,现在可以让你比较" RedGreenBlue彼此相关。但有没有什么方法可以让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不知道应如何实现它们的函数}}。对于某些类型类,例如BaseballPlayerShowEq等,功能很简单,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

自动派生使您更容易避免样板。自动派生的最常见类型类是ShowEq,因为编译器可以为这些类型类生成非常合理的值。