Zna*_*atz 10 haskell typeclass newtype
在真实世界Haskell的第321页
有这些代码,
...
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype AInt = A { unA::Int }
deriving (Show, Eq, Num)
instance Monoid AInt where
mempty = 0
Run Code Online (Sandbox Code Playgroud)
我的困惑是为什么
mempty = 0
Run Code Online (Sandbox Code Playgroud)
但不是
mempty = A 0
Run Code Online (Sandbox Code Playgroud)
?
我也注意到了这两点
ghci> 0 :: AInt
Run Code Online (Sandbox Code Playgroud)
和
ghci> A 0 :: AInt
Run Code Online (Sandbox Code Playgroud)
给我同样的回应
A { unA = 0 }
Run Code Online (Sandbox Code Playgroud)
有人请告诉我这两个有什么区别?
Tik*_*vis 14
这里的诀窍是GeneralizedNewtypeDeriving扩展.特别是,只要底层类型是实例,这就允许我们为a 派生任何类newtype.所有这一切都是将实例从旧类型复制到新类型.
在这种特殊情况下,AInt派生出来Num.这意味着这AInt是一个Num使用相同代码的实例Int(包含在A构造函数中的所有内容).这包括Int的fromInteger功能.
该fromInteger功能在来定义Int的fromInteger,看起来像这样:
fromInteger i = A (fromInteger i)
Run Code Online (Sandbox Code Playgroud)
因为0是多态的 - 它具有类型0 :: Num a => a--it是任何类型的有效常量Num.感谢newtype派生,这包括AInt使用fromInteger上面的函数.这意味着0 :: AInt一个人之间确实没有区别A 0 :: AInt.
ham*_*mar 12
类似的数字文字0被重载并具有类型0 :: Num a => a,这意味着它们可以是具有Num实例的任何类型,具体取决于上下文.这通过类型类中的fromInteger函数发生Num,因此当您键入时,0它被视为您已编写fromInteger 0.
通过使用GeneralizedNewtypeDeriving,GHC(实际上1)Num为您的类编写了一个实例,如下所示:
instance Num AInt where
fromInteger n = A (fromInteger n)
...
Run Code Online (Sandbox Code Playgroud)
因此,当你写作时0 :: AInt,这会扩展到fromInteger 0 :: AInt(通过上面的定义)等于A (fromInteger 0)哪个与你写的相同A 0.
1 GeneralizedNewtypeDeriving实际上并没有写一个新的intance.它只是执行必要的强制转换以使用现有的强制转换.