10

Real World Haskell的第 321 页上

有这些代码,

...

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype AInt = A { unA::Int }
    deriving (Show, Eq, Num)

instance Monoid AInt where
    mempty = 0

我的困惑是为什么

mempty = 0

但不是

mempty = A 0

?


我还注意到两者

ghci> 0 :: AInt

ghci> A 0 :: AInt

给我同样的回应

A { unA = 0 }

有人能告诉我这两个有什么区别吗?

4

2 回答 2

14

这里的诀窍在于GeneralizedNewtypeDeriving扩展。特别是,只要底层类型是实例,我们就可以派生任何类。newtype所有这一切都是将实例从旧类型复制到新类型。

在这种特殊情况下,AInt派生Num. 这意味着这AInt是一个Num使用相同代码的实例Int(所有内容都包含在A适当的构造函数中)。这包括Int'fromInteger功能。

fromInteger函数是根据Int's定义的fromInteger,看起来像这样:

fromInteger i = A (fromInteger i)

由于是多态0——它具有类型——它0 :: Num a => a对于. 多亏了新类型的派生,这包括, 使用上面的函数。这意味着.NumAIntfromInteger0 :: AIntA 0 :: AInt

于 2013-04-16T04:31:39.640 回答
12

像这样的数字文字0被重载并具有 type 0 :: Num a => a,这意味着它们可以是任何有Num实例的类型,具体取决于上下文。这是通过类型类中的fromInteger函数发生的,因此当您键入时,它会被视为您编写了.Num0fromInteger 0

通过使用GeneralizedNewtypeDeriving,GHC (实际上是1Num )为您的类编写了一个实例,如下所示:

instance Num AInt where
  fromInteger n = A (fromInteger n)
  ...

因此,当您编写 时0 :: AInt,这将扩展fromInteger 0 :: AInt为(根据上面的定义)等于与A (fromInteger 0)您编写的相同A 0

1 GeneralizedNewtypeDeriving实际上并没有写一个新的实例。它只是执行必要的强制转换以使用现有的强制转换。

于 2013-04-16T04:31:15.580 回答