Reputation: 2967
I am slightly confused by the interleave function given in this guide.
I have the following data type:
data M m r = Atomic (m (M m r)) | Done r
I've created a lifting function to take a m a
, inserts the a
inside Done
, and then re-inserts Done a
back into m ()
. This forms the Atomic
structure:
atm :: Monad m => m a -> M m a
atm m = Atomic $ liftM Done m
I've made M m
an instance of the Monad
class (which pattern matches based on data constructor):
instance (Monad m) => Monad (M m) where
return = Done
(Atomic m) >>= f = Atomic liftM (>>= f) m
(Done r) >>= f = f v
There's a simple implementation function which accesses nested values within the Atomic wrapper
:
runThread :: Monad m => M m a -> m a
runThread (Atomic m) = m >>= runThread --Extract m and recursively pass to runThread
runThread (Done r) = return r --Return Done
Then, there is the following interleave function:
interleave :: Monad m => M m r -> M m r -> M m r
interleave (Atomic m1) (Atomic m2) = do
next1 <- atm m1 --?
next2 <- atm m2 --?
interleave next1 next2
interleave (Done _) t2 = interleave t2
interleave t1 (Done _) = interleave t1
My points of confusion are at next1 <- atm m1
and next2 <- atm m2
.
As I understand it, all this is doing is taking m1
from the (Atomic m1)
wrapper and reinserting it back into an Atomic
wrapper? How is this operation interleaving?
Am I missing something basic here? The code works fine, so I'm sure it's due to my confusion.
The rest of the code:
threadOne :: M IO ()
threadOne = do
atm $ print 1
threadTwo :: M IO ()
threadTwo = do
atm $ print 2
main = do
runThread (interleave threadOne threadTwo)
Upvotes: 3
Views: 155
Reputation: 19637
You are partially right. The code
next1 <- atm m1
takes the atomic action that the first thread starts with and inserts it into the merged/interleaved thread. What's returned from the call to atm
is the continuation next1
of that first thread.
But next, we are taking an action from the second thread, by saying
next2 <- atm m2
So the merged thread ends up executing an action from the first thread, and then one from the second thread. Hence "interleaving". We then continue by calling interleave
recursively on the two continuations via
interleave next1 next2
Upvotes: 2