What is the FlexibleContexts extension good for? Could you please explain it using a simple example?

Without FlexibleContexts all typeclass constraints on function definitions must have type variables. For example:

add :: Num a => a -> a -> a 
add = (+)

Where a is the type variable. With FlexibleContexts enabled you can have any type inside a typeclass.

intAdd :: Num Int => Int -> Int -> Int 
intAdd = (+)

This example is pretty contrived but it is the simplest I can think of. FlexibleContexts is usually only used with MultiParamTypeClasses. Here is an example:

class Shower a b where
  myShow :: a -> b

doSomething :: Shower a String => a -> String
doSomething = myShow

Here you can see we say that we only want a Shower a String. Without FlexibleContexts String would have to be a type variable instead of a concrete type.


Commonly it's used with the MultiParamTypeClasses extension, for example when using the mtl library you might write

doSomethingWithState :: MonadState MyState m => m ()
doSomethingWithState = do
    current <- get
    let something1 = computeSomething1 current
        something2 = computeSomething2 current something1
    put something2

And similarly with MonadReader and MonadWriter, along with other similar typeclasses. Without FlexibleContexts you can't use this constraint.

(Note that this answer was based on @DiegoNolan's but rewritten to use an existing library that should make sense to LYAH readers).


I've discovered a use for it apart from those mentioned: it results in clearer error messages from GHC. E.g. normally,

Prelude> max (1, 2) 3

<interactive>:1:1: error:
    • Non type-variable argument in the constraint: Num (a, b)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall a b.
              (Num (a, b), Num b, Num a, Ord b, Ord a) =>
              (a, b)

And with FlexibleContexts enabled:

Prelude> max (1, 2) 3

<interactive>:1:1: error:
    • No instance for (Num (Integer, Integer))
        arising from a use of ‘it’
    • In the first argument of ‘print’, namely ‘it’
      In a stmt of an interactive GHCi command: print it

Here's a discussion.

Tags:

Haskell

Ghc