Equality constraints (Haskell)

{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
class Twice1 f where
  twice1 :: f -> f

class Twice2 f where
  twice2 :: f -> f

instance Twice1 (a -> a) where
  twice1 f = f . f

instance (a ~ b) => Twice2 (a -> b) where
  twice2 f = f . f
  
class Example a where
  transform :: Int -> a

instance Example Int where
  transform n = n + 1

instance Example Char where
  transform _ = 'x' 
  
apply1 x = twice1 transform x
apply2 x = twice2 transform x

apply1 :: (Example a, Twice1 (Int -> a)) => Int -> a
apply2 :: Int -> Int

For apply1 we don’t have sufficient information from transform’s type (Int -> a) and the context.

For apply2 we have information from the context, which asserts that a ~ b. Hence when a ~ Int, b ~ Int.

Reference: