在Haskell中覆盖+

时间:2018-10-02 20:14:15

标签: function haskell matrix types constructor

我试图覆盖+符号,以了解如何定义自己的类型。我是Haskell的新手,似乎无法克服此错误。

这是我简单的新类型:

newtype Matrix x = Matrix x
(+):: (Num a, Num b, Num c) => Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]
x + y = Matrix zipWith (\ a b -> zipWith (+) a b) x y

当我尝试将其加载到ghci中时,出现错误

linear_algebra.hs:9:42:
    Ambiguous occurrence ‘+’
    It could refer to either ‘Main.+’, defined at linear_algebra.hs:9:3
                          or ‘Prelude.+’,
                             imported from ‘Prelude’ at linear_algebra.hs:1:1
                             (and originally defined in ‘GHC.Num’)
Failed, modules loaded: none.

代替我的最后一行代码
x + y = Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y

给我错误

    Couldn't match expected type ‘([Integer] -> [Integer] -> [Integer])
                                  -> Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]’
                with actual type ‘Matrix
                                    ((a0 -> b0 -> c0) -> [a0] -> [b0] -> [c0])’
    Relevant bindings include
      y :: Matrix [[b]] (bound at linear_algebra.hs:9:5)
      x :: Matrix [[a]] (bound at linear_algebra.hs:9:1)
      (+) :: Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]
        (bound at linear_algebra.hs:9:1)
    The function ‘Matrix’ is applied to four arguments,
    but its type ‘((a0 -> b0 -> c0) -> [a0] -> [b0] -> [c0])
                  -> Matrix ((a0 -> b0 -> c0) -> [a0] -> [b0] -> [c0])’
    has only one
    In the expression:
      Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y
    In an equation for ‘+’:
        x + y = Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y
Failed, modules loaded: none.

能否请您帮助我了解错误所在?我真的很感激。谢谢!

1 个答案:

答案 0 :(得分:7)

首先,类型

(+) :: (Num a, Num b, Num c) => Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]

太笼统了。它指出,即使元素类型不同,也可以将任何数字矩阵与任何其他数字矩阵求和,以生成第三个数字类型的矩阵(可能与前两个数字类型不同)。也就是说,特别是可以将浮点矩阵求和为双精度矩阵,以生成整数矩阵。

您要代替

(+) :: Num a => Matrix [[a]] -> Matrix [[a]] -> Matrix [[a]]

我建议将“列表列表”类型移到新类型内

newtype Matrix a = Matrix [[a]]

反映出列表的列表实现了Matrix的概念。给出类型签名

(+) :: Num a => Matrix a -> Matrix a -> Matrix a

要“覆盖” (+):Haskell中没有覆盖/重载。最接近的选项是:

  1. 定义模块本地函数(+)。这将与Prelude.(+)发生冲突,因此现在需要对每个+进行限定,以消除歧义。我们无法编写x + y,但是我们需要x Prelude.+ yx MyModuleName.+ y

  2. Num实现Matrix a实例。这不是一个好主意,因为矩阵不完全是一个数字,但是我们仍然可以尝试。

    instance Num a => Num (Matrix a) where
       Matrix xs + Matrix ys = Matrix (zipWith (zipWith (+)) xs ys)
       -- other Num operators here
      (*) = error "not implemented" -- We can't match dimension
      negate (Matrix xs) = Matrix (map (map negate) xs)
      abs = error "not implemented"
      signum = error "not implemented"
      fromInteger = error "not implemented"
    

    这与您的代码非常相似,缺少一些括号。并非所有其他方法都可以完全有意义地实现,因为Num是用于数字而不是矩阵。

  3. 使用其他运算符,例如(^+)或其他