mstade/funkis — pull request #10 by mstade (2014-04-22 15:00:28+00:00)
Title: Channels for communicating sequential processes

Starting this PR as a WIP on channels. This work will likely also include – or depend on – protocols, multiple/predicate dispatch, and futures.

Channels are a nice way to provide an abstraction for processes communicating with one another. They act a lot like sequences, with the exception that values may not be immediately available. As such, there's a need to find a useful abstraction for future values. Promises as they are specified in ES6 are an over engineered mess, and while they may well be supported as return values for non-blocking channels, they probably shouldn't be the recommended mechanism.

One thing I'd like to accomplish with channels is to make them act largely the same as sequences – that is, they are a view on to a data structure. The main difference however, is that sequences are blocking and immediate, so when realizing a value (i.e. calling `rest` or `first`) that value is immediately available. Of course, the value may be a future, meaning the consumer will have to add a function to be called once the future value is available. (Which may be immediately, in which case the future is effectively the same as `constantly`.) The benefit of this is that function such as `take`, `map`, etc. works regardless of what, where, or when the structure is available. To make for nice syntax, something similar to Clojure's `go` blocks make sense. Here's a contrived mockup:

```javascript
const tick = timer(5000)
, log = console()

go(function *() {
yield take(1, tick)
put(log, "Five seconds later, I feel refreshed.")
})
```

In this example, `tick` and `log` are channels that are used in `go` block which takes care of the boilerplate of dealing with futures returned from `yield take(1, tick)`. Using sequences like this implies that the sequence is fully realized before the execution is resumed. This may be magical, and some care might be required to deal with it. Here's another example, where an infinite channel is used:

```javascript
const brush = mouse()

go(function *() {
while(brush.open) {
const points = yield take(4, brush)
draw(canvas, bezier(points))
}
})
```

The imaginary `draw` function is used to output pixels on to a canvas (this, as it were, could also be a channel, but I'm choosing to not go the shiny-hammer route just yet) by virtue of taking 4 points and making a [Bézier curve][1] out of them.

[1]: https://en.wikipedia.org/wiki/B%C3%A9zier_curve

In both of these mockups, generators are used to suspend execution. Since funkis is largely a research project, I don't think there's much need to limit it to ES5 environments. Should that be the case however, it may be worth looking into something like [degenerate][2].

A benefit to using something like `go` blocks is that routines can be made into values to pass around and compose. Here's an expansion of the drawing mockup above:

```javascript
const brush = mouse()

go(comp(curve, noise)(brush))

function * curve(brush) {
while(brush.open) {
const points = yield take(4, brush)
draw(canvas, bezier(points))
}
}

function * noise(brush) {
const perturbed = chan()
yield perturbed

while (brush.open) {
var co = yield take(1, brush)
put(map(co, perturb))
}

function perturb(d) {
return d + random(0, 1)
}
}
```

This is a mockup, so there are a bunch of assumptions made (like, what's `random`, `draw` etc.?) but it ought to show the general direction in which I hope this work will go. The idea is to have a simple abstraction of a sequence of values, where not only is the underlying data structure not important but neither is the point in time when values are available.

Work in progress, so things are bound to change, but this marks a start.

[2]: https://github.com/Gozala/degenerate