【问题标题】:Overriding + in Haskell [duplicate]在 Haskell 中覆盖 + [重复]
【发布时间】:2018-10-02 20:14:14
【问题描述】:

我正在尝试覆盖 + 符号以学习如何定义我自己的类型。我对 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.

你能帮我理解错误是什么吗?我真的很感激。谢谢!

【问题讨论】:

  • 不能在 Haskell 中覆盖,只能实现一个类型类,比如Num 类型类:learnyouahaskell.com/…
  • 坦率地说,让Matrix 成为Num 的实例是没有意义的。 (你可以,如果你真的想......但是矩阵的符号是什么?fromInteger 3 应该计算成什么矩阵?)
  • 请务必仔细阅读错误消息“...函数‘Matrix’应用于四个参数,但它的类型只有一个,在表达式Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y...中”。你缺少括号

标签: function haskell matrix types constructor


【解决方案1】:

首先是类型

(+) :: (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. Matrix a 实现一个Num 实例。这不是一个好主意,因为矩阵并不完全是一个数字,但无论如何我们都可以尝试。

    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. 使用不同的运算符,例如(^+) 之类的

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 2015-06-29
    • 2013-12-12
    • 2011-05-13
    • 2020-05-23
    • 2012-12-16
    • 2013-06-11
    相关资源
    最近更新 更多