Know what would be awesome? If you could use the monad syntax to clean up async, cb-passing code. I've been learning a lot of Haskell lately too, and I like to think of the monads as returning a set of instructions with side effects to be executed in order. I think this example is kind of trivial. I'd love to see one that does something more than simple addition (IO!)
...
(* long_running_call : unit -> string Deferred.t *)
long_running_call ()
>>= fun result ->
print_endline result
...
Running calls in parallel is easy. Say we want to run a couple of queries against a db at once, and only perform an action once both return:
...
(* Db.query : Db -> Db.Query -> Db.Result Deferred.t *)
let d1 = Db.query db query1 in
let d2 = Db.query db query2 in
d1 >>= fun r1 ->
d2 >>= fun r2 ->
...
Doesn't this have the same problem that Python's Twisted does -- that async calls may lack handlers for error conditions, and so errors may be silently ignored?
Async includes a module called Monitor that lets you correctly handle exceptions in async code. The signature of one of the most commonly used methods is this:
It takes two arguments. Name is used to tell you what monitor the error was caught by. The second is a function that returns some kind of Deferred.t. The whole thing returns a (deferred) Result.t (: [`Ok of 'a | `Error of exn]), letting you either do something with the results of the async call or handle the error. Usage might be something like this:
(* query_or_print : Db.t -> Db.Query.t -> Db.Result.t option Deferred.t *)
let query_or_print db query =
Monitor.try_with (fun () -> Db.query db query)
>>| function
| `Ok result -> Some result
| `Error e -> print_endline (Exn.to_string e); None