Reputation:
data V2 a = V2 a a deriving (Show, Eq)
instance Num a => Num (V2 a) where
(-) (V2 x0 y0) (V2 x1 y1) = V2 (x0 - x1) (y0 - y1)
(+) (V2 x0 y0) (V2 x1 y1) = V2 (x0 + x1) (y0 + y1)
(*) (V2 x0 y0) (V2 x1 y1) = V2 (x0 * x1) (y0 * y1)
abs = undefined
signum = undefined
fromInteger = undefined
instance Fractional a => Fractional (V2 a) where
(/) (V2 x0 y0) (V2 x1 y1) = V2 (x0 / x1) (y0 / y1)
recip = undefined
fromRational = undefined
-- Multiply by scalar
(*$) :: Num a => V2 a -> a -> V2 a
(*$) (V2 x y) s = V2 (x * s) (y * s)
-- Length of the vector
len :: (Num a, Integral a, Floating b) => V2 a -> b
len (V2 x y) = sqrt $ fromIntegral $ x * x + y * y
normal :: (Num a, Integral a) => V2 a -> V2 a
normal v = v *$ (1 / len v)
{-
Math\V2.hs:31:20:
Could not deduce (Fractional a) arising from a use of `/'
from the context (Num a, Integral a)
bound by the type signature for
normal :: (Num a, Integral a) => V2 a -> V2 a
at Math\V2.hs:31:1-27
Possible fix:
add (Fractional a) to the context of
the type signature for
normal :: (Num a, Integral a) => V2 a -> V2 a
In the second argument of `(*$)', namely `(1 / len v)'
In the expression: v *$ (1 / len v)
In an equation for `normal': normal v = v *$ (1 / len v)
Math\V2.hs:31:22:
Could not deduce (Floating a) arising from a use of `len'
from the context (Num a, Integral a)
bound by the type signature for
normal :: (Num a, Integral a) => V2 a -> V2 a
at Math\V2.hs:31:1-27
Possible fix:
add (Floating a) to the context of
the type signature for
normal :: (Num a, Integral a) => V2 a -> V2 a
In the second argument of `(/)', namely `len v'
In the second argument of `(*$)', namely `(1 / len v)'
In the expression: v *$ (1 / len v)
-}
I am having trouble implementing the normal function above. How can get it to pass the type check?
Upvotes: 0
Views: 1792
Reputation: 3927
Three options:
Change your type signature:
normal :: (Integral a, Floating b) => V2 a -> V2 b
And then specify a function to convert a (Integral a) => V2 a
into a (Floating b) => V2 b
and apply that to the v
before the *$
.
Convert the Floating
result from the 1 / len v
into an Integral
value (round
, etc.).
Do as Landei suggests and force usage of Floating
everywhere.
len
takes in a (Integral a) => V2 a
and returns a (Floating b) => b
. You then do 1 /
on the result, which still has type (Floating b) => b
. From your type of *$
, it takes a V2 a
and an a
, but in this case you have v :: (Integral a) => V2 a
and (1 / len v) :: (Floating b) => b
which aren't equivalent types.
So you have to do some form of coercion somewhere.
Upvotes: 4
Reputation: 13677
The minimal fix is just to change type signature for normal:
normal :: Floating a => V2 a -> V2 a
Here are the types:
sqrt :: Floating a => a -> a
So there's no reason for len to accept something other than Floating
.
Upvotes: 1
Reputation: 22636
Found it. As len
is returning a floating, a needs to be floating in normal
. Otherwise
you can try to define
($*) :: Num a, ?b => V2 a -> b -> V2 a
Anyay
normal :: (Num a, Integral a, Floating a) => V2 a -> V2 a
works
You can alternatively change you len definition to be
len :: (Num a ) => V2 a -> a
Upvotes: -1
Reputation: 54584
How about...
len :: (Floating a) => V2 a -> a
len (V2 x y) = sqrt $ x * x + y * y
normal :: (Floating a) => V2 a -> V2 a
normal v = v *$ (1.0 / len v)
Of course that means that you need to convert a V2 Int
before you can calculate the normal, but this is like you have to convert an Int before doing division.
Upvotes: 0