当我在左边放置一个双矩阵而在右边放一个Double时,为什么( - )无法进行类型检查?

时间:2016-08-18 22:02:10

标签: haskell hmatrix

由于hmatrix为Matrix类型提供了Num的实例,我可以表达基于元素的减法:

m = (2><2)[1..] :: Double Matrix
m' = m - 3

效果很好,因为3Num,并且会导致通过从m的每个元素中减去3来创建矩阵。

为什么这不起作用:

m' = m - (3::Double)

我得到的错误是:

Couldn't match expected type ‘Matrix Double’
            with actual type ‘Double’
In the second argument of ‘(-)’, namely ‘(3 :: Double)’
In the expression: m - (3 :: Double)

我希望编译器能够理解Double也是Num。为什么看起来不是这样?

2 个答案:

答案 0 :(得分:7)

使用m - 3 m :: Matrix Double 3 :: Matrix Double时,Matrix Double会发生什么。 Num3的实例的事实意味着编译器知道如何翻译文本m - (3 :: Double)。但是,当您执行(-) :: (Num a) => a -> a -> a时,由于Num而出现类型错误,因此您减去的元素的类型必须是Double的实例并且匹配。因此,您可以减去两个Matrix Double,两个Matrix Double,但不能减去Double imageBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);

毕竟,这对我来说似乎是合乎逻辑的,减去矩阵和标量是没有意义的。

答案 1 :(得分:5)

这是对Haskell基于类型的重载类型的新手的常见误解,特别是那些习惯于在流行的OO语言中使用的基于子类的重载的人。

减法运算符的类型为Num a => a -> a -> a;所以它需要类型类Num中的任何类型的两个参数。 似乎就像你做m - 3时发生的那样是减法运算符在左边接受Matrix Double而在右边接受一些简单的数字类型。但这实际上是不正确的。

当像Num a => a -> a -> a这样的类型签名多次使用相同的类型变量时,您可以选择您喜欢的任何类型(在这种情况下,受=>Num a之前的约束条件限制)要用于a,但必须<{>>完全相同的类型 a出现的地方。 Matrix Double -> Double -> ???不是Num a => a -> a -> a类型的有效实例化(如果是,您如何知道它返回的内容?)。

m - 3工作的原因是因为两个参数必须是同一类型,而m肯定是类型Matrix Double,编译器会看到3也必须是Matrix Double类型。因此,它不使用源文本中出现的3来构建Double(或Integer,或许多其他数字类型之一),而是使用源文本3建立一个Matrix Double。实际上,类型推断改变了编译器读取源代码文本3的方式。

但是如果你使用m' = m - (3::Double)那么你不会让它只是弄清楚3必须具有什么类型才能使减法运算符有效,你告诉它3 1}}具体是Double两个事实都没有办法(你的:: Double断言以及减法运算符得到两个相同类型的参数的要求),所以你得到一个类型错误。