【问题标题】:Why does Either derives Show but Maybe does not?为什么 Either 派生 Show 但 Maybe 没有?
【发布时间】:2015-01-07 22:10:34
【问题描述】:

EitherMaybe 的文档表明它们有 Show 的实例。

Either 被定义为派生Show,简单地说:

data  Either a b  =  Left a | Right b
  deriving (Eq, Ord, Read, Show, Typeable)

然而,Maybe 没有:

data  Maybe a  =  Nothing | Just a
  deriving (Eq, Ord)

既然它们是base 的一部分并且非常相似,为什么Maybe 不直接派生Show

另一个问题也可能是,它的Show 实例是从哪里获得的?

【问题讨论】:

    标签: haskell show maybe either deriving


    【解决方案1】:

    Maybe 的实例在GHC.Show 中显式定义,还有一大堆其他常见类型(如元组)的实例。您可以使用ghci 中的:i 命令找出实例的定义位置:

    Prelude> :i Maybe
    data Maybe a = Nothing | Just a     -- Defined in ‘Data.Maybe’
    instance Eq a => Eq (Maybe a) -- Defined in ‘Data.Maybe’
    instance Monad Maybe -- Defined in ‘Data.Maybe’
    instance Functor Maybe -- Defined in ‘Data.Maybe’
    instance Ord a => Ord (Maybe a) -- Defined in ‘Data.Maybe’
    instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
    instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
    

    我不知道他们为什么明确定义实例或将其放入 GHC.Show 而不是 Data.Maybe — 据我所知,它可以移动到 Data.Maybe 和/或派生。我的猜测是他们不希望 Data.Maybe 依赖于除 GHC.Base 之外的任何东西(就像现在一样),大概是因为它被用于其他一些核心模块中。

    【讨论】:

      【解决方案2】:

      AFAIK 元组没有在任何地方定义,因此为了避免孤立实例[1],必须在 GHC.Show[2] 中定义元组的 Show 实例。这些实例的实现恰好使用foldr1

      show_tuple :: [ShowS] -> ShowS
      show_tuple ss = showChar '('
                    . foldr1 (\s r -> s . showChar ',' . r) ss
                    . showChar ')'
      

      所以 GHC.Show 在定义该函数的地方导入 GHC.List。反过来,GHC.List 定义了lookup,它位于Maybe monad 中(我猜是老Haskell 98 的单态偏差)。所以 GHC.List 导入 Data.Maybe。为了定义Show 实例,Data.Maybe 需要(直接或间接)导入 GHC.Show,这将使整个序列 GHC.Show -> GHC.List -> Data.Maybe -> GHC.Show循环依赖。 GHC 不能很好地支持循环依赖(并不是说它们很容易支持!),所以 base 很难避免它们。

      [1] 孤立实例是在与实例中涉及的类和类型不同的模块中定义的实例。形式上,Haskell 要求在被编译的模块直接或间接导入的任何模块中进行实例搜索;但对于非孤儿实例,GHC 可以将其短路,只需查看两个地方。对于孤儿实例,它必须跟踪模块中的每个孤儿实例,然后跟踪这些实例被导入它们的每个模块重新公开,这更昂贵(并且意味着它必须保持一个上下文环境,其中可能包含许多实例甚至与当前模块无关,因为它实际上并没有导入这些类或类型)。因此,好的做法是避免出现孤儿实例。

      从哲学上讲,孤儿实例是在程序中获取同一类/类型的两个冲突实例的一种非常好的方法,因为它们在您的Main 模块中都是“可见的”,这意味着它们会发生冲突。所以语言功能本身有点狡猾。

      [2] IIRC GHC 仅提供最多(相对较小)固定数量的元组组件的 Show 实例,这不是 相当 Haskell 98 兼容,但足以用于任何实际编程需要。 (说真的,无论如何都不要使用超过 3 个元素的元组,您忘记特定组件的含义)。我不知道在过去几年中是否更新了标准以使 GHC 符合要求。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-13
        • 2017-11-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多