创建Num类的实例

时间:2014-12-13 19:45:20

标签: haskell

我对学习哈斯克尔相对较新。

我有以下抽象数据类型

data Scalar = 
    Scalar Integer
  deriving (Eq, Show)

我希望能够在Scaler类型上执行以下操作:

> (Scalar 10) + 1
> Scalar 11

要做到这一点,我尝试将Scalar类的num实例设为这样:

instance Num Scalar where
  (Scalar i1) + i2 = (Scalar (i1+i2))

但这不起作用。我究竟做错了什么?最新的方法是什么?

修改 我得到的错误是:

Couldn't match expected type `Integer' with actual type `Scalar '
In the second argument of `(+)', namely `i2'
In the first argument of `Scalar ', namely `(i1 + i2)'

4 个答案:

答案 0 :(得分:5)

不,你不能这样做,因为+的类型是:

λ> :t (+)
(+) :: Num a => a -> a -> a

因此,它对相同数据的类型进行操作。在您的情况下,您尝试添加一种无效的ScalarInteger类型。您可以定义这样的实例:

instance Num Scalar where
    (Scalar i1) + (Scalar i2) = Scalar (i1 + i2)

它将在Scalar类型:

上运行
λ> Scalar 3 + Scalar 4
Scalar 7

但如果您真的想这样做,可以为此创建自己的特殊功能:

addNumtoScalar :: Integer -> Scalar -> Scalar
addNumtoScalar x (Scalar y)  = Scalar (x + y)

然后您可以使用此功能添加

λ> addNumtoScalar 3 (Scalar 7)
Scalar 10

或者以中缀方式:

λ> 3 `addNumtoScalar` (Scalar 7)
Scalar 10

正如@ user5402所评论的那样,您可以定义fromInteger类型类的Num函数,然后在添加中使用它。像这样:

instance Num Scalar where
    (Scalar x) + (Scalar y) = Scalar (x + y)
    fromInteger x = Scalar x

现在,您可以使用整数文字,并在必要时将它们自动转换为Scalar值,例如:

λ> 3 + Scalar 7
Scalar 10

答案 1 :(得分:2)

您无法添加ScalarInteger(例如Scalar 10 + 1);你应该在添加之前将第二个值包装在Scalar中。因此,您的实例应如下所示:

instance Num Scalar where
  (Scalar i1) + (Scalar i2) = (Scalar (i1+i2))

但是,Num类型类提供了除+之外还需要实现的其他几种方法。您可以使用GHC GeneralizedNewtypeDeriving扩展来处理所有这些内容,而不是手动编写所有内容:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Scalar = Scalar Integer deriving (Eq,Show,Num)

这将根据Num实现Scalar类型类的方式自动派生Integer Num个实例。这种方法要求您使用新类型,但听起来它适合您的用例。

答案 2 :(得分:1)

首先,你的定义有问题:

(Scalar i1) + i2 = (Scalar (i1+i2))

应该如下:

(Scalar i1) + (Scalar i2) = Scalar (i1+i2)

其次,如果你看一下documentation of the Num typeclass

您将看到有关最小完整定义的部分。

(+), (*), abs, signum, fromInteger, (negate | (-))

您已经实施了(+),但没有实施其他任何内容。

最后,如果您发布了问题,请提供您正在获取的错误。

祝你好运

答案 3 :(得分:0)

正如其他人已经指出+两侧的类型需要匹配。您可以做的是定义自定义运算符以添加ScalarInt

(+.) :: Scalar -> Int -> Scalar
(Scalar i1) +. i2 = Scalar (i1 + i2)

infixl 6 +.

您可能还想使用newtype包装器(您只需将data关键字替换为newtype)。这在语义上是相同的(除了在一些具有未定义值的极端情况下)但效率稍高,因为在编译期间会删除newtypes。