类型类实例中的类型类约束

时间:2018-07-10 08:14:28

标签: haskell typeclass

您好,在阅读《真实世界》 Haskell书中的示例时,我遇到了这个示例,我无法理解它的含义以及它是如何工作的: instance Num a=>Num (SymbolicManip a)
在这种情况下,我应该翻译为:“对于类型SymbolicManip的Num实例,其类型a的字段存在一个约束,即:a是一个实例本身”? 有人可以告诉我我是否正确解释或解释?
为什么instance Num (SymbolicManip a)还不够?

-- The "operators" that we're going to support
data Op = Plus | Minus | Mul | Div | Pow
        deriving (Eq, Show)

{- The core symbolic manipulation type -}
data SymbolicManip a = 
          Number a           -- Simple number, such as 5
        | Arith Op (SymbolicManip a) (SymbolicManip a)
          deriving (Eq, Show)

{- SymbolicManip will be an instance of Num.  Define how the Num
operations are handled over a SymbolicManip.  This will implement things
like (+) for SymbolicManip. -}
instance Num a => Num (SymbolicManip a) where
    a + b = Arith Plus a b
    a - b = Arith Minus a b
    a * b = Arith Mul a b
    negate a = Arith Mul (Number (-1)) a
    abs a = error "abs is unimplemented"
    signum _ = error "signum is unimplemented"
    fromInteger i = Number (fromInteger i)

PS 所有代码均来自本书( 13-子章-扩展示例-数值类型)

2 个答案:

答案 0 :(得分:5)

请务必注意,SymbolicManip a不能是Num的实例,而没有a也是Num的实例,因此,就像我们向函数添加约束时一样,我们可以为类型类添加约束:

 instance Num a => Num (SymbolicManip a) where
 --       ^^^^^^^^ "As long as `a` is an instance of `Num`..."
 --                ^^^^^^^^^^^^^^^^^^^^^ "...so is `SymbolicManip a`"

我们必须包括Num a =>约束,因为在实现中,我们使用fromInteger来产生类型为a的成员。 不可避免,就像向函数Numexample a b = 2*a + b添加example :: Num a => a -> a -> a约束一样。

这是一个简单的例子。考虑这种类型:

newtype Identity a = Identity a

请注意,Identity a可以是Num的实例,只要a也是Num,那么,我们添加一个约束:

instance Num a => Num (Identity a) where
-- (...)

答案 1 :(得分:3)

这意味着,如果aNum的实例,那么SybolicManip a也是Num的实例。

所以,如果您有:

x :: SymbolicManip Integer
y :: SymbolicManip Integer

然后,您可以编写x+y,而无需定义含义。但是,如果相反,您尝试添加两个SymbolicManip String值,则会出现类型错误,因为String不是Num的实例。

如果查看实例,您将看到negatefromInteger都使用Num的功能。因此,如果您取消约束,则编译器将给出有关无法推断aNum实例的错误。