The issue is a bit subtle but the compiler is right in this case: parts of the code are ambiguous. If we look at the default definition for norm
:
norm x = wrap $
(un x) - (un turn) * (fromIntegral . floor ) ( (un x) / (un turn))
There are two places where the expression un turn
appears. What is the type of this expression? It is:
un turn :: (Angle b, Floating x) => b x
I’m using b
instead of a
intentionally: it can be any Angle
! There is nothing here telling the compiler that the types of x
and turn
are equal. There are several ways to fix this, the most explicit one being just adding type signatures.
This requires us to turn on ScopedTypeVariables
at the top of the file, so that we can refer to the type variable x
inside an expression:
{-# LANGUAGE ScopedTypeVariables #-}
And then we can fix this issue by telling the compiler which Angle
to use (a x
):
class Angle a where
-- normalizes the angle
norm :: forall x. (RealFrac x, Floating x) => a x -> a x
norm x = wrap $ (un x) - (un (turn :: a x)) * (fromIntegral . floor ) ( (un x) / (un (turn :: a x)))
I had to add this signature to a few other places in the file as well, but that made it compile.