In a general exercise about concurrency based on this article.
We have:
-- a is the result type on which after we continue
type Continuation a = a-> Action
type ContinuationPseudoMonad a = Continuation a -> Action
-- pseudoMonad because it will need Concurrent wrapper Monad:
-- so as to define bind operation and return operation on it
data Concurrent a = Concurrent (ContinuationPseudoMonad a)
so Concurrent a
is a monad we have to implement with its two mandatory laws, return and bind.
Unfortunatly, I find no adequate words for defining more precisely the ContinuationPseudoMonad thing... and if I lack words, I lack abstraction in my mind.
How would you call it ?
Is there a word meaning Continuation a -> Action
instead of my awkward meaningless ContinuationPseudoMonad
?
Action being:
data Action = Atom (IO Action)
| Fork Action Action
| Stop
It is evident Concurrent a
is the same as Cont Action a
where Cont
is the continuation monad. Here's a simple explanation for continuations:
f :: a -> b
for some arbitrary types a
and b
. We want to convert this function into continuation passing style. How do we do so?k :: b -> r
which takes the return value of f
as an input and itself returns a value of an arbitrary type r
. Following this, we can convert f
to CPS.g :: a -> (b -> r) -> r
be the CPS version function of f
. Note that it takes an additional argument (i.e. the continuation k
) and returns the result of k
applied to its output b
.Let's take a practical example where f
is the predicate function odd :: Int -> Bool
:
odd :: Int -> Bool
odd n = n `mod` 2 == 1
Here's the same function written in continuation passing style:
odd' :: Int -> (Bool -> r) -> r
odd' n k = k (n `mod` 2 == 1)
The (Bool -> r) -> r
part can be abstracted out as the continuation monad:
data Cont r a = Cont { runCont :: (a -> r) -> r }
odd' :: Int -> Cont r Bool
odd' n = return (n `mod` 2 == 1)
instance Monad (Cont r) where
return a = Cont (\k -> k a)
m >>= f = Cont (\k -> runCont m (\a -> runCont (f a) k))
Notice that the type of the continuation k
is Bool -> r
for some arbitrary type r
. Hence, the continuation k
could be any function which takes a Bool
as an argument. For example:
cont :: Bool -> IO ()
cont = print
main :: IO ()
main = odd' 21 cont
However, in the case of Concurrent
this r
is not arbitrary. It has been specialized to Action
. In fact, we can define Concurrent
as a type synonym for Cont Action
as follows:
type Concurrent = Cont Action
Now, we don't need to implement the Monad
instance for Concurrent
because it's the same as the Monad
instance for Cont r
as defined above.
runConcurrent :: Concurrent a -> ContinuationPseudoMonad a
runConcurrent (Concurrent g) = g
instance Monad Concurrent where
return a = Concurrent (\k -> k a)
m >>= f = Concurrent (\k -> runConcurrent m (\a -> runConcurrent (f a) k))
Note that nowhere in the definition of instance Monad Concurrent
have we made use of Action
. That's because Concurrent = Cont Action
and the monad instance of Cont r
uses r
transparently.