对非参数化数据类型使用加号运算符

时间:2014-01-04 02:19:58

标签: haskell

我有一个包含“添加”操作的简单类

class (Eq a, Show a, Read a) => Group a where 
  add :: a -> a -> a

我使用一个构造函数参数创建了一个名为“Z5”的新数据类型,namly是一个int值:

data Z5 = Z5 Int deriving (Eq, Read, Show)   

数据类型的实例化如下所示:

instance Group (Z5) where
  add x y = x+y

问题是我收到错误消息:

 No instance for (Num Z5) arising from a use of `+'
 Possible fix: add an instance declaration for (Num Z5)

我用

尝试了
instance (Num Z5) => Group (Z5) where
 add x y = x+y

但是错误信息是:

 Non type-variable argument in the constraint: Num Z5
 (Use -XFlexibleContexts to permit this)
 In the context: (Num Z5)
 While checking an instance declaration
 In the instance declaration for `Group (Z5)'

2 个答案:

答案 0 :(得分:5)

此错误非常简单:No instance for (Num Z5) arising from a use of `+'。您需要Z5的'Num'实例。您有几种选择:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Z5 = Z5 Int deriving (Eq, Read, Show, Num)   

这会为您的类型创建一个与Num相同的Int实例。或者,您可以手动编写实例,如果您不希望它与Num的实例相同。

instance Num Z5 where
     (Z5 a) + (Z5 b) = Z5 (a + b + 5) -- you can do whatever you like here

编写约束C T C是一个类型类而T是一个单态类型总是毫无意义;这将是真的,在这种情况下你不需要编写约束,或者它将是false,在这种情况下它将不会编译。

更一般地说,Num的任何实例都是一个数学组,所以你可以写:

-- This newtype is defined in Data.Monoid
newtype Sum a = Sum a
instance Num a => Group (Sum a) where 
  add (Sum a) (Sum b) = Sum (a + b) 
  identity = Sum 0
  invert (Sum x) = Sum (-x)

然后你可以做以下事情:

>add ((Sum 4) :: Sum Z5) ((Sum 5) :: Sum Z5)
Sum {getSum = Z5 9}

答案 1 :(得分:4)

您的意思是直接在您的原始代码中使用+ Z5类型,或者您是想写一个

instance Group Z5 where
  add (Z5 x) (Z5 y) = Z5 (x+y)

+操作仅适用于数字(即Num类型类的实例),因此您无法自动将其用于自定义数据类型,例如Z5