Sergey Kumkov
Sergey Kumkov

Reputation: 43

Illegal instance declaration in Haskell

I tried the following code

class Group a where
  (.+.) :: a -> a -> a
  (.-.) :: a -> a -> a
  zero :: a
  opposite :: a -> a

  x .-. y = x .+. opposite y
  opposite x = zero .-. x
  {-# MINIMAL (.+.), zero, (opposite | (.-.)) #-}

instance Fractional a => Group a where
  x .+. y = x + y
  zero = 0 :: a
  opposite = negate :: a -> a

But on loading into GHCi, I get the following error:

group1.hs:11:26: error:
    • Illegal instance declaration for ‘Group 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 ‘Group a’
   |
11 | instance Fractional a => Group a where
   |    

What am I doing wrong?

Upvotes: 1

Views: 653

Answers (2)

talex
talex

Reputation: 20566

I was able to compile your example:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

class Group a where
  (.+.) :: a -> a -> a
  (.-.) :: a -> a -> a
  zero :: a
  opposite :: a -> a

  x .-. y = x .+. opposite y
  opposite x = zero .-. x
  {-# MINIMAL (.+.), zero, (opposite | (.-.)) #-}

-- data Fractional a = Fractional a a

instance (Fractional a, Num a) => Group a where
  x .+. y = x + y
  zero = 0
  opposite = negate
  • FlexibleInstances allow instance of unknown type with constraints. Basically allow instance X a
  • UndecidableInstances we need because we declare that any a belong to class Group and it could (inevitable?) lead to a belong to Group thru several different instance declarations.

Upvotes: 2

Sergey Kumkov
Sergey Kumkov

Reputation: 43

Ah! I have finally understood, what is wrong. In Haskell, a class can be instantiated for an ADT only. So, the only reasonable solution is to declare something as follows:

class Group a where
  (.+.) :: a -> a -> a
  (.-.) :: a -> a -> a
  zero :: a
  opposite :: a -> a

  x .-. y = x .+. opposite y
  opposite x = zero .-. x
  {-# MINIMAL (.+.), zero, (opposite | (.-.)) #-}

newtype GroupType a = GroupType a  

instance Fractional a => Group (GroupType a) where
  GroupType x .+. GroupType y = GroupType $ x + y
  zero = GroupType 0
  opposite (GroupType x) = GroupType $ negate x

Upvotes: 3

Related Questions