Programmer
Programmer

Reputation: 375

In Haskell, when we use a do block, how does it figure out which monad to be used?

We know that the do block is just syntactic sugar. But then how does it figure out which monadic context it is in? Assume we don't use <- operator anywhere in the do block.

Upvotes: 3

Views: 1588

Answers (2)

MathematicalOrchid
MathematicalOrchid

Reputation: 62848

Maybe some "practical" examples will help:

foo1 = do
  print 5
  return 7
-- print belongs to the IO monad. This whole thing is in IO.

foo2 x = do
  writeTVar x 7
  return 11
-- writeTVar belongs to the STM monad. This whole thing is in STM.

foo3 = do
  let x = 5
  [1, 2, 3, 4]
-- Last line is a list expression. This whole thing is in the list monad.

foo4 = do
  put 7
  return 9
-- put is in the State monad. This whole thing is in the state monad.

foo5 = do
  x <- magic1
  y <- magic2
  return (x, y)
-- This is in whatever monad magic1 and magic2 are in.

foo6 = do
  return 13
-- Doesn't mention any monad. Works for ALL POSSIBLE MONADS!

foo7 abc def = do
  x <- abc
  y <- def
  return (x, y)
-- Runs in whatever monad abc and def run in.
-- By passing different arguments, you can CHANGE which monad that is!

Upvotes: 7

daniel gratzer
daniel gratzer

Reputation: 53901

It uses the same general type class mechanism that is used to figure out which + to use or even what numeric type to use for literals. That is, something like

 do
    return True

Will not divine the specific monad that it should use but rather just be assigned the type Monad m => m Bool. This constraint says that the do-block has the type m Bool for any m which happens to have implemented the Monad type class. Moreover, whenever this block is used, the specific instance will be inferred from the context of its use.

If we use operators that are tied to a specific Monad, this will force the type to become more specific. For instance, if we use modify :: (a -> a) -> State s a -> State s () (I'm simplifying the type for the sake of example here) then this will force the block to have the type State s .... In general, Haskell will figure out the most general type possible and make use of type class constraints to make sure that the types in question implement the appropriate operations.

Upvotes: 10

Related Questions