繁体   English   中英

在 Haskell 中推导是什么/意味着什么?

[英]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 类型类的函数,例如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工作,我们实现了一个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

粗略地说,这现在允许您相互“比较” 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)

然而,关键在于:对于任意用户定义的类型类,当您尝试将类型类与诸如ColorBaseballPlayer之类的数据类型相关联时,GHC 不知道它们的功能应该如何实现。 对于某些类型类,例如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 ,但这是另一天:)

在这种特定情况下,它会为您的类型生成一个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一起工作的函数。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM