Skip to content

Instantly share code, notes, and snippets.

@szabi
Last active May 12, 2020 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szabi/412c88f7ad383c1c3a1704f6642eec72 to your computer and use it in GitHub Desktop.
Save szabi/412c88f7ad383c1c3a1704f6642eec72 to your computer and use it in GitHub Desktop.
Could not deduce <instance> arising from...
module Angle where
{- | Type-class for angle units.
This library provides @Rad@ (radians) and @Deg@ (degrees), but you could
define e.g. Gon. The instance definition takes the value of a turn.
-}
class Angle a where
-- how many UNITS does a whole turn have?
turn :: Floating x => a x
-- normalizes the angle
norm :: (RealFrac x, Floating x) => a x -> a x
norm x = wrap $ (un x) - (un turn) * (fromIntegral . floor ) ( (un x) / (un turn))
-- automatic conversion for
toRad :: Floating x => a x -> Rad x
toRad = Rad . toRad'
toRad' :: Floating x => a x -> x
toRad' x = (un x) / (un turn) * 2 * pi
fromRad :: Floating x => Rad x -> a x
fromRad x = wrap $ (un turn) * (unRad x / 2 / pi)
-- technical to be able to refer to construct and deconstruct the values
-- in the default definitions
un :: a x -> x
wrap :: x -> a x
{-# MINIMAL turn, un, wrap #-}
{- | An angle in radians. @Rad@ is provided by this library and is used
internally to define default implementations for arbitrary units.
-}
newtype Rad x = Rad { unRad :: x } deriving (Eq, Ord, Show)
instance Angle Rad where
un = unRad
wrap = Rad
turn = Rad (2 * pi)
-- we specialize toRad and fromRad here
toRad = id
toRad' = unRad
fromRad = id
-- | An angle in degrees.
newtype Deg x = Deg { unDeg :: x } deriving (Eq, Ord, Show)
instance Angle Deg where
un = unDeg
wrap = Deg
turn = Deg 360
src/Angle.hs:12:30-36: error:
• Could not deduce (Angle a0) arising from a use of ‘un’
from the context: Angle a
bound by the class declaration for ‘Angle’
at src/Angle.hs:7:8-12
or from: (RealFrac x, Floating x)
bound by the type signature for:
norm :: forall x. (RealFrac x, Floating x) => a x -> a x
at src/Angle.hs:11:15-53
The type variable ‘a0’ is ambiguous
These potential instances exist:
instance Angle Deg -- Defined at src/Data/Angle.hs:46:10
instance Angle Rad -- Defined at src/Data/Angle.hs:35:10
• In the first argument of ‘(*)’, namely ‘(un turn)’
In the second argument of ‘(-)’, namely
‘(un turn) * (fromIntegral . floor) ((un x) / (un turn))’
In the second argument of ‘($)’, namely
‘(un x) - (un turn) * (fromIntegral . floor) ((un x) / (un turn))’
|
12 | norm x = wrap $ (un x) - (un turn) * (fromIntegral . floor ) ( (un x) / (un turn))
| ^^^^^^^
@szabi
Copy link
Author

szabi commented May 12, 2020

I am perplexed by the error message. I assumed when compiling line 12, GHC would simply refer to the definition of turn in line 9. This seems straightforward and the types are compatible, but GHC seems to insist to check for concrete instances instead of the type in the class definition when type checking and deferring resolution until later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment