Reputation: 780
I'm trying to make a typeclass for signed numerical types. Here's my code:
{-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances #-}
data Sign = Negative | Zero | Positive
deriving (Eq, Ord, Read, Show)
class Signed a where
sign :: a -> Sign
instance Signed Integer where
sign = undefined
This compiles, but I'd like to adapt this code to work on any Integral a
.
instance (Integral a) => Signed a where
sign = undefined
At which point it fails to compile.
I've checked Haskell type family instance with type constraints, but that seems to be addressing a different problem from mine. I don't think there's a syntax error, in my code.
Upvotes: 3
Views: 631
Reputation: 44654
Attempting to compile your code produces the following error message:
sign.hs:9:26:
Illegal instance declaration for ‘Signed a’
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use FlexibleInstances if you want to disable this.)
In the instance declaration for ‘Signed a’
Failed, modules loaded: none.
As the compiler points out, you need to turn on FlexibleInstances
as well as UndecidableInstances
. GHC's error messages are usually quite specific, especially when you've forgotten to turn on a language extension. The following compiles right away:
{-# LANGUAGE UndecidableInstances, FlexibleInstances #-}
data Sign = Negative | Zero | Positive
deriving (Eq, Ord, Read, Show)
class Signed a where
sign :: a -> Sign
instance (Integral a) => Signed a where
sign = undefined
However, I think the Signed
class may be a mistake in this example. Defining a (non-overloaded) top-level function is much simpler, doesn't require UndecidableInstances
(the need for which is often a design smell), and is more expressive of the meaning of your code: the "things you can get the sign of" are precisely the real numbers.
sign :: Real a => a -> Sign
sign x
| x == 0 = Zero
| x < 0 = Negative
| otherwise = Positive
Upvotes: 2