Monads/Promises have been our go to tools for expressing concurrency.
However, they seem to divide up our language.
We constantly look for ways to execute a piece of code after a certain operation.
let url = "https://api.my-service.com/";
fetch(url)
|> Js.Promise.then_( ... )
/* This point on, we are trapped in the world of
promises */
Monads also create the divide in the language.
Promises are, after all, monadics interfaces
They provide us with ability to define the semantics of elsewhere (handlers)
effect V : int
let rec sum_up () =
perform V
let () =
let v =
try sum_up () with
| effect V k ->
continue k 667
in
Printf.printf "Value received is %d\n" v
effect Conversion_failure : string -> int
let int_of_string l =
try int_of_string l with
| Failure _ -> perform (Conversion_failure l)
let rec sum_up acc =
let l = input_line stdin in
acc := !acc + int_of_string l;
sum_up acc
let _ =
let r = ref 0 in
try sum_up r with
| End_of_file -> Printf.printf "Sum is %d\n" !r
| effect (Conversion_failure s) k ->
Printf.fprintf stderr "Conversion failure \"%s\"\n%!" s;
continue k 0
- Computational effects/side effects/Purity
- Asynchronous programming
- Usefulness in writing schedulers (OCaml multicore, React team)
- Alternative control flow (think generators, async/await, coroutines, iterators)
Algebraic Effects for the rest of us
https://overreacted.io/algebraic-effects-for-the-rest-of-us/
What goes into crafting a programming language with Effects?
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/08/algeff-tr-2016-v2.pdf
Avoiding large monolithic runtimes by letting programs write their own schedulers
https://kcsrk.info/papers/effects_ocaml15.pdf
All major concurrency primitives convered - async/await, fibers, co-routines, continuations, delimited continuations and algebraic effects
https://www.yld.io/blog/continuations-coroutines-fibers-effects/