sweet-fantasies
sweet-fantasies copied to clipboard
Updates macros for Sweet.js 0.6.x
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:
- 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 toa.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(?) - Do blocks are wrapped in a immediately forced thunk. This was again mainly for simplicity with dealing with variable bindings.
- 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.
- 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.
Nice, you beat me to it :)
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?)