What is the FlexibleContexts extension good for? Could you please explain it using a simple example?
I was trying to understand what the FlexibleContexts extension is doing by searching for web pages that would explain it to mere mortals (people who have read LYHFGG, for example, like me) but I did not find any such resource.
Therefore I ask the experts on the topic: Could you please explain what this extension does, why it exists, and give one or two simple examples how and why one should use it?
Furthermore, If I am reading someone else's code which uses this extension, then what should I know about the extension in order to understand the code written using this extension?
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).