3

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.

Community
  • 1
  • 1
Fried Brice
  • 769
  • 7
  • 20
  • You'd need to turn on `OverlappingInstances`, I think. On the other hand, I think putting `sign` in a class may be a mistake in this case - just define a top-level function `sign :: Integral a => a -> Sign`. – Benjamin Hodgson Nov 08 '15 at 23:27
  • Just tried it. Doesn't seem to change. `instance Signed Integer` still compiles, but `instance (Integral a) => ...` still fails. – Fried Brice Nov 08 '15 at 23:29
  • 1
    OK, I put your code into a file and GHC told me I needed to turn on `FlexibleInstances` too. With that, it compiles right away. (GHC's error messages are usually quite specific about which extensions you need to turn on.) – Benjamin Hodgson Nov 08 '15 at 23:31
  • You're right. It does tell me... Thank you. – Fried Brice Nov 08 '15 at 23:33

1 Answers1

2

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
Benjamin Hodgson
  • 42,952
  • 15
  • 108
  • 157