sweet-fantasies icon indicating copy to clipboard operation
sweet-fantasies copied to clipboard

Updates macros for Sweet.js 0.6.x

Open robotlolita opened this issue 10 years ago • 2 comments

This addresses (https://github.com/puffnfresh/sweet-fantasies/issues/8), it's mainly a complete rewrite of the do notation macro. Other macros should probably be dropped now and rewritten using Sweet.js's custom operators (http://sweetjs.org/doc/main/sweet.html#custom-operators), as they make more sense as infix.

This patch also supports having a naked action as the last expression, so:

var a = $do {
  x <- f()
  y <- g()
  h(x, y)
}

Works and gets desugared as expected:

var a = (function() {
  return f().chain(function(x) {
    return g().chain(function(y) {
      return h(x, y)
    })
  })
}())

A couple of things worth noting about this patch:

  1. Actions that aren't bound to an explicit identifier gets bound to _it. This was mainly for simplicity dealing with all the cases, so: $do { a; b } gets desugared to a.chain(_it => b). I'm unsure if this is much of a problem, though this does introduce an implicit new binding in the scope, which might lead to some awkward things(?)
  2. Do blocks are wrapped in a immediately forced thunk. This was again mainly for simplicity with dealing with variable bindings.
  3. The patch makes use of an experimental feature in Sweet.js 0.6.x (http://sweetjs.org/doc/main/sweet.html#custom-pattern-classes-experimental) to abstract over some patterns. This is mainly to allow constructs to be optionally separated with a semicolon, I'm unsure to which extent this is actually useful.
  4. This patch does not support multiple returns. I'm unsure if this was supported before? It should be reasonably doable though, and I'll give it a go once I've got a little bit more of time.

robotlolita avatar Jun 15 '14 14:06 robotlolita

Nice, you beat me to it :)

SimonRichardson avatar Jun 16 '14 09:06 SimonRichardson

So, I took a stab at multiple returns, but there's some issues with it. The following code:

$do {
  x <- Identity.of(a)
 someAction()
  y <- return b + x
  return y + 1
}

Gets expanded to:

(function () {
    var $do$op = Identity.of(a);
    var $do$of = $do$op.of || $do$op.constructor.of;
    return $do$op.chain(function (x) {
        return someAction().chain(function (_it) {
            return $do$of(b).chain(function (y) {
                return $do$of(c);
            });
        });
    });
}());

Rather than the simpler:

(function () {
  return Identity.of(a).chain(funciton(x) {
    return someAction()
  }).map(function(_it) {
    return b + x
  }).map(function(y) {
    return y + 1
  })
}())

The meaning is the same, but the generated code is quite a bit more messy. Generating the simpler version should be possible, but would be quite a bit more of work. What do y'all think?

Oh, it also relies on the assumption that the $do block is well typed. If someone writes something like $do { x <- Identity.of(a); y <- Async.of(b); return c } then the behaviour will be different (but in this case, I do guess the behaviour of that whole thing is undefined anyway?)

robotlolita avatar Jun 17 '14 20:06 robotlolita