Type class constraints in type signature inside an instance when the type is a free variable

Viewed 396

How can I add type class constraints in type signature inside an instance when the type is a free variable in Haskell. For example:

{-# LANGUAGE InstanceSigs #-}

class Pair a where
    pair :: a -> b -> (a, b)

instance Pair Int where
    pair :: (Show a) => a -> b -> (a, b)
    pair a b = (a, b)

works, 'a' is a bound type variable whereas:

{-# LANGUAGE InstanceSigs #-}

class Pair a where
    pair :: a -> b -> (a, b)

instance Pair Int where
    pair :: (Show b) => a -> b -> (a, b)
    pair a b = (a, b)

gives this error:

source_file.hs:8:13:
    No instance for (Show b)
    Possible fix:
      add (Show b) to the context of
        the type signature for pair :: Int -> b -> (Int, b)
    When checking that: forall a b. Show b => a -> b -> (a, b)
      is more polymorphic than: forall b. Int -> b -> (Int, b)
    When checking that instance signature for ‘pair’
      is more general than its signature in the class
      Instance sig: forall a b. Show b => a -> b -> (a, b)
         Class sig: forall b. Int -> b -> (Int, b)
    In the instance declaration for ‘Pair Int’
2 Answers

At the conceptual-intuitive level, the class Pair is a promise to the consumer. It says "there is this function pair, which will work for this type a and any other type b". Anybody who sees the class can use the function with any type b.

But your instance is trying to say "I'll implement this function pair, but only for bs which have a Show instance". Well, this is not a complete implementation of the class: the class promises to work for any b, but the instance works only for some bs.

You can't.

The type of pair is forall a b. Pair a => a -> b -> (a, b).

Where a = Int, this specializes to forall b. Int -> b -> (Int, b).

In the first example, your type declaration forall a b. Show a => a -> b -> (a, b) specializes to forall b. Show Int => Int -> b -> (Int, b), and then further reduces to forall b. Int -> b -> (Int, b). (The Show constraint just gets dropped because it is redundant; you're "constraining" a concrete type, which is meaningless.) This is the correct type.

In the second example, you're trying to define an instance where pair has the type forall b. Show b => Int -> b -> (Int, b), which doesn't work because that's a different type.

Related