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.

4
  • 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. Commented Nov 8, 2015 at 23:27
  • Just tried it. Doesn't seem to change. instance Signed Integer still compiles, but instance (Integral a) => ... still fails. Commented Nov 8, 2015 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.) Commented Nov 8, 2015 at 23:31
  • You're right. It does tell me... Thank you. Commented Nov 8, 2015 at 23:33

1 Answer 1

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
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for giving such a helpful answer. Glad I can get rid of the typeclass and pragmas.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.