The definition you are looking for reads something like
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) f))
How did we get there? As always, we let the types do the work. :)
Let us first introduce a helper function:
runConcurrent :: Concurrent b -> (b -> Action) -> Action
runConcurrent (Concurrent h) = h
If you start out with the left-hand side of your definition
Concurrent h >>= k = ...
with h :: (a -> Action) -> Action
and k :: a -> Concurrent b
, then your goal is to replace ...
with an expression of type Concurrent b
, isn't it?
How can we construct a value of type Concurrent b
? One way is to apply our function k
, but that won't work, because we don't have a suitable value of type a
available as an argument. So, pretty much the only thing we can do is to apply the data constructor Concurrent
which is of type ((b -> Action) -> Action) -> Concurrent b
.
That gives:
Concurrent h >>= k = Concurrent ...
Now we have to go and find us an expression of type (b -> Action) -> Action
to supply as an argument for Concurrent
. We know that expressions of function type can always be constructed through lambda-abstraction:
Concurrent h >>= k = Concurrent (\f -> ...)
This gives us f :: b -> Action
and the obligation to replace ...
with an expresion of type Action
. Using one of the Action
-constructors directly would be cheating of course ;). To guarantee the genericity of (>>=)
(more precisely, to make sure that we end up obeying the monad laws), we treat Action
as if it's an abstract datatype. Then, the only way to produce an Action
-value is to apply the function h
:
Concurrent h >>= k = Concurrent (\f -> h ...)
Hence, next we need to supply h
with an argument of type a -> Action
. That is a function type again, so we throw in another lambda:
Concurrent h >>= k = Concurrent (\f -> h (\x -> ...))
Hence, we have x :: a
and need to construct a body of type Action
. What can we do with a value of type a
? We can supply it to the function k
. This gives us a value of type Concurrent b
, which we can then pass to our helper function runConcurrent
:
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) ...))
This gives us a function of type (b -> Action) -> Action
and supplying f
as an argument does the trick:
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) f))