Reason: Built in syntax for async.

Created on 14 Mar 2016  Â·  14Comments  Â·  Source: reasonml/reason

I've really liked Lwt's syntax for async (including the integration with try, let, and let + and for simultaneously async calls). We can bake this into Reason by default with something like let!, and then allow configuration of which library it should represent.

Imagine putting an attribute at the top of the file such as:

[@async Lwt];

or

[@async Async];

which could influence which library is used for that first class let binding syntax.

For the implementation, we could reuse Lwt's ppx plugin perhaps.

RFC

Most helpful comment

F# computation expressions are nice. You can specify the “builder” outside the let! block so you can have let! with different meaning in one file depending on the context.

All 14 comments

Syntax for monadic code will interact well with implicits: if you desugar

 let! x = e in
 let! y = e' in
   return (g x y)

into

 e >>= fun x ->
 fun e' >>= fun y ->
 return (g x y)

then you can just use implicits to pick the appropriate implementation of >>=.

Since the desugaring should be the same in any case, even without implicits you can write something like this

  Lwt.(
   let! x = e in
   let! y = e' in
   return (g x y)
  )

to avoid the need for a magic attribute.

What would be the default? Optionals?
That would be useful.

F# computation expressions are nice. You can specify the “builder” outside the let! block so you can have let! with different meaning in one file depending on the context.

Yes, I also think that the F# async ability to select the desired monad on a per-block rather than per-file basis is a significant benefit. Nesting them (essentially shadowing the outer let! by the inner one) also ought to work.

@gaearon That sounds like what I'm describing with attributes. You can put the "provider" of that asynchronicity at the to of the file, or even scoped to some lexical block, because you can place attributes anywhere in the tree.

Ah okay, I didn’t realize

you can place attributes anywhere in the tree

Ah okay, I didn’t realize

It's not obvious, and that doesn't mean it won't require some effort to replicate the nice scoping rules of lexical scoping.

We might be able to do it without attribute nodes in the AST, and instead just open the right module.

@yallop Have you seen Lwt's ppx extension? It seems to do that and much more (considers and bindings as being parallel, also unifies match/with with this same monadic concept). I am very much looking forward to modular implicits as well.

@jordwalke: I'm not that familiar with Lwt's ppx extension, but I know Jane Street's ppx_let, which does something similar (including parallel computation support for let ... and) and various other implementations. I think the important thing is to have two independent components:

  1. a way to desugar things like let into things like >>=. There are a few choices here (Lwt's ppx extension, ppx_let, ...)
  2. a way to choose _which_ >>= to use in a particular block of code. This should be a separate step from desugaring and is best done via core language mechanisms such as local opens or implicits.

I'm probably missing some context here, but if ! means what I think it means, how would you express the following (which is valid using Babel/regenerator in JavaScript today) in Reason:

async function(): Promise<void> {
  if (await someCall()) {
    const [first, second] = Promise.all([thisReturnsAPromise(), thisAlsoReturnsAPromise()]);
  }
}

I believe there was a proposal to add syntactic sugar for Promise.all() that died, which would have allowed for something like:

async function(): Promise<void> {
  if (await someCall()) {
    const [first, second] = await* thisReturnsAPromise(), thisAlsoReturnsAPromise();
  }
}

See also #1321

i think that with my proposal, await can be an ordinary suspendable function.
async can be an ordinary function that wraps a lambda in a promise.
No need to create more syntax, since internal DSLs assembles language itself using functions.
https://github.com/facebook/reason/issues/1982

let myAsyncFunc = async {
  body
};

await @@ myAsyncFunc();

No need to reinvent the wheel, some languages already have the battle tested solution to this.

https://github.com/facebook/reason/issues/1982 internal DSLs + coroutines "aka suspendable functions".

This can probably be closed now that Reason supports OCaml's monadic/applicative let syntax, yes?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rickyvetter picture rickyvetter  Â·  4Comments

kyldvs picture kyldvs  Â·  3Comments

ostera picture ostera  Â·  3Comments

gustavopinto picture gustavopinto  Â·  3Comments

braibant picture braibant  Â·  4Comments