Reputation: 1082
Since hmatrix provides an instance of Num for Matrix types, I can express element-wise subtraction like:
m = (2><2)[1..] :: Double Matrix
m' = m - 3
That works great, as 3
is a Num
, and results in a matrix created by subtracting 3 from each element of m
.
Why does this not also work:
m' = m - (3::Double)
The error I'm getting is:
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)
I expected the compiler to understand that a Double
is also a Num
. Why is that seemingly not the case?
Upvotes: 1
Views: 90
Reputation: 71495
This is a common misunderstanding of people new to Haskell's style of typeclass based overloading, especially those who are used to the subclass-based overloading used in popular OO languages.
The subtraction operator has type Num a => a -> a -> a
; so it takes two arguments of any type that is in the type class Num
. It seems like what is happening when you do m - 3
is that the subtraction operator is accepting a Matrix Double
on the left and some simple numeric type on the right. But that is actually incorrect.
When a type signature like Num a => a -> a -> a
uses the same type variable multiple times, you can pick any type you like (subject to the contstraints before the =>
: Num a
in this case) to use for a
but it has to be the exact same type everywhere that a
appears. Matrix Double -> Double -> ???
is not a valid instantiation of the type Num a => a -> a -> a
(and if it were, how would you know what it returned?).
The reason m - 3
works is that because both arguments have to be the same type, and m
is definitely of type Matrix Double
, the compiler sees that 3
must also be of type Matrix Double
. So instead of using the 3
appearing in the source text to build a Double
(or Integer
, or one of many other numeric types), it uses the source text 3
to build a Matrix Double
. Effectively the type inference has changed the way the compiler reads the source code text 3
.
But if you use m' = m - (3::Double)
then you're not letting it just figure out what type 3
must have to make the use of the subtraction operator valid, you're telling it that this 3
is specifically a Double
. There's no way both facts to be true (your :: Double
assertion and the requirement that the subtraction operator gets two arguments of the same type), so you get a type error.
Upvotes: 5
Reputation: 461
What happens when you do m - 3
with m :: Matrix Double
is that 3 :: Matrix Double
. The fact that Matrix Double
is an instance of Num
means that the compilers knows how to translate the litteral 3
. However when you do m - (3 :: Double)
, you get a type error because (-) :: (Num a) => a -> a -> a
, so the type of the element you subtract must be instances of Num
and match. Hence you can subtract two Double
s, two Matrix Double
s but not a Matrix Double
and a Double
.
After all, this seems fairly logical to me, it doesn't make sense to subtract a matrix and a scalar.
Upvotes: 7