在 Haskell 中导出 do/mean 是什么意思?

What does deriving do/mean in Haskell?

堆栈溢出派生的定义是:

"In Haskell, a derived instance is an instance declaration that is generated automatically in conjunction with a data or newtype declaration. The body of a derived instance declaration is derived syntactically from the definition of the associated type."

老实说,我一点都不懂。

以下代码摘自:Link

data BaseballPlayer = Pitcher 
                        | Catcher
                        | Infielder
                        | Outfielder
                        deriving Show

barryBonds :: BaseballPlayer -> Bool
barryBonds Outfielder = True

barryInOf = print(barryBonds Outfielder)

我的问题是,在这种特定情况下,派生语句的作用是什么, 以及推导语句的一般作用是什么?

派生意味着您的数据类型自动能够 "derive" 特定类型 类 的实例。在这种情况下 BaseballPlayer 派生 Show 这意味着我们可以使用任何需要 Show 实例的函数来处理 BaseballPlayer.

自动推导让您更容易避免样板。自动推导最常见的类型类是ShowEq,因为编译器可以为这些类型类.

做出非常合理的值

在这种特定情况下,它会为您的类型生成一个 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 class 成员完成的,但这并不重要。

简而言之:

deriving 自动实现一些 Haskell 类型 class 的功能,例如 ShowEq。这不能用任意类型 classes 来完成,但是 deriving 确实适用的类型足够简单,可以自动实现。

Show 类型class 定义了如何将数据类型表示为 String 的函数。

更广泛:

你熟悉类型class吗?

https://www.haskell.org/tutorial/classes.html

Typeclasses 类似于 Java 中的接口:它们定义了一些函数,任何想要使用这些函数的数据类型都可以实现。

例如,假设我们有一个像这样的 class:

class Comparable a where
    lessThan :: a -> a -> Bool
    equalsTo :: a -> a -> Bool

注意class这个词。它意味着在 Haskell 设置中键入 class,而不是您在面向对象语言中听到的典型 "class"。这里的 a 是一个填充类型,类似于您期望模板在 C++ 中的工作方式和泛型在 Java.

中的行为方式

假设我们定义一个数据类型如下:

data Color = Red | Green | Blue

为了使 ComparableColor 一起工作,我们实现了 Comparableinstance

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

粗略地说,这现在允许您 "compare" RedGreenBlue 彼此。但是有没有什么方法可以让 GHC 自动猜出这正是您想要的 "order"?

退一步说,类型class 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 中的函数可以根据彼此定义。事实上,我们也可以轻松做到:

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)

然而,关键在于:对于任意用户定义的类型classes,当你试图将类型class与数据类型,例如 ColorBaseballPlayer。对于一些类型class例如ShowEqOrd等,在功能足够简单的情况下,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 的功能,但那是以后的事了:)