Reputation: 213
Why the relationship between a
and b
is not deducible?
class Vector a where
(<.>) :: Num b => a -> a -> b
data Vec2 a
= Vec2 (a, a)
deriving Show
instance Num a => Vector (Vec2 a) where
Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d
I would like to have a Vec2 algebric data structure where components can be any numbers.
Upvotes: 1
Views: 67
Reputation: 116139
(<.>) :: Num b => a -> a -> b
The above means that (<.>)
is able to produce any type of number the caller of that function might want.
For instance, if x,y
are Vec2 Double
, then x <.> y
can be called to return Integer
. The compiler then complains that its implementation in the posted instance is not general enough, because it returns Double
s instead of any type the caller might choose.
I think this is not what that code was intended to model.
You might want to switch to a multiparameter class (you'll need to enable a few extensions, GHC will tell you which ones):
class Vector a b where
(<.>) :: a -> a -> b
instance Num a => Vector (Vec2 a) a where
Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d
Since now the compiler can not determine the type of x <.> y
from the type of x,y
, you might want to add a functional dependency using
class Vector a b | a -> b where
(<.>) :: a -> a -> b
or alternatively to use a type family
class Vector a where
type Scalar a
(<.>) :: a -> a -> Scalar a
instance Num a => Vector (Vec2 a) where
type Scalar (Vec a) = a
Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d
Upvotes: 7
Reputation: 18189
As @chi's answer said, your code doesn't make b
depend on a
. To get what I think you want, you can use an associated type family:
{-# LANGUAGE TypeFamilies #-}
class Vector a where
type Element a
(<.>) :: a -> a -> Element a
data Vec2 a
= Vec2 (a, a)
deriving Show
instance Num a => Vector (Vec2 a) where
type Element (Vec2 a) = a
Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d
Another option is to use a multiparameter typeclass with a functional dependency, but I think that's more complicated here.
Upvotes: 2