I watch this video and starts at 6min35s, it mentioned this graph:
saying that the IO Monad makes it easy to handle concurrency. I got confused on this: how does it work? How do the two for comprehension
enable the concurrency (the computation of d
and f
)?
for
comprehensions only help you omitting several parentheses and indents.
The code you referred, translate to [flat]map
is strictly equivalent to:
async.boundedQueue[Stuff](100).flatMap{ a =>
val d = computeB(a).flatMap{
b => computeD(b).map{ result =>
result
}
}
val f = computeC(a).flatMap{ c =>
computeE(c).flatMap{ e =>
computeF(e).map{ result =>
result
}
}
}
d.merge(f).map(g => g)
}
See, it only helps you omitting several parentheses and indents (joke)
flatMap
and map
Once you understand how for
is translated to flatMap
and map
, you can implement your concurrency inside them.
As map
takes a function as argument, it doesn't mean that the function is executed during execution of map
function, you can defer the function to another thread or run it latter. This is how concurrency implemented.
Take Promise
and Future
as example:
val future: Future = ```some promise```
val r: Future = for (v <- future) yield doSomething(v)
// or
val r: Future = future.map(v => doSomething(v))
r.wait
The function doSomething
is not executed during the execution of Future.map
function, instead it is called when the promise
commits.
How to implement concurrency using for
syntax suger:
for
will convert into flatMap
and map
by scala compilerflatMap
and map
, where you will get a callback function from argumentThe flow control feature of many languages share a same property, they are like delimited continuation shift/reset
, where they capture the following execution upto a scope into an function.
JavaScript:
async function() {
...
val yielded = await new Promise((resolve) => shift(resolve))
// resolve will captured execution of following statements upto end of the function.
...captured
}
Haskell:
do {
...
yielded_monad <- ```some monad``` -- shift function is >>= of the monad
...captured
}
Scala:
for {
...
yielded_monad <- ```some monad``` // shift function is flatMap/map of the monad
...captured
} yield ...
next time you see a language feature which capture following execution into a function, you know you can implement flow control using the feature.
The difference between delimited continuation and call/cc is that call/cc capture the whole following execution of the program, but delimited continuation has a scope.