Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

Oh yeah, CallStream is great to express monads

It has been pointed out by several commenters that CallStream was a reinvention of monads. Not quite so, but the nuance is subtle.

CallStream is a pattern to express chain-callable APIs. That makes it possible to express monads with CallStream, but in the same way that JavaScript functions and C# delegates do.

Expressing monads with CallStreams can be done in a way that is quite expressive, but let me switch from the usual C# to JavaScript for that (I can’t think of a strongly-typed C# expression of the same thing, but feel free to prove me wrong in the comments).

Here’s the code for the monad:

function identity(value) {
    var bind = function (operation) {
        return operation(value);
    }
    bind.value = value;
    return bind;
}

And here’s how you would use it:

var a = identity("some string")
  (function(s) {
return identity(s + " was processed by identity.");
}) (function(s) {
return identity(s + " And it's chainable...");
}) .value;

This is the strict identity monad. The unit or boxing function is the identity function, the unboxing is done by getting the value property, and binding is done by using the monadic instance (the result of calling identity) as a function that takes the operation as its argument.

We can relax the monad definition like we did with the C# identity implementation from my first monad post by calling identity from the monad’s code instead of leaving that responsibility to the operation code:

function identity(value) {
    var bind = function (operation) {
        return identity(operation(value));
    }
    bind.value = value;
    return bind;
}

The use of the monad is then simplified:

var a = identity("some string")
    (function(s) { return s + " was processed by identity."; })
    (function(s) { return s + " And it's chainable..."; })
    .value;

We can also express the stateful monad:

function stateful(value, state) {
    var bind = function (operation) {
        return stateful(operation.call(bind, value), bind.state);
    }
    bind.value = value;
    bind.state = state;
    return bind;
}

And use it as follows:

var p = stateful(3, "This is the state");
         (function (i) { return ++i; })
         (function (i) { this.state += " altered"; return i * 10; })
         (function (i) { return i + 2; });
alert("Value: " + p.value + "; state: " + p.state);

Note how the operation is getting called through JavaScript Function’s call method, which enables us to set the meaning of “this” from within the function body. That’s what enables one of the operations to manipulate the state through this.state.

Now if only JavaScript had a Lambda syntax so that we could stop writing function(i) {…return…}…

The original CallStream post:
http://dbj.org/dbj/?p=514

Comments

DBJ said:

V. good BLR. Although I would (perhaps) appreciate a more direct link to the CallStream inventor ;)

Also, my personal recommendation would be :

var p = stateful(3, "This is the state");

        (function (i) { return ++i; })

        (function (i) { this.state += " altered"; return i * 10; })

        (function (i) { return i + 2; });

// DBJ: no reason to "derail" the stream

(function () {

alert("Value: " + p.value + "; state: " + p.state);

}) ;

That is, an callback use to get to the value in the "back".

Good post, indeed, I am gratefull for your "evangelising" of the CallStream ;)

--DBJ

--DBJ

# July 4, 2010 3:31 PM

Bertrand Le Roy said:

Ah, yes, you are absolutely right. I added a link.

My reason for "derailing" the stream was to illustrate the unboxing of the value and state from the monad.

# July 11, 2010 2:59 PM

DBJ said:

The subtle but unavoidable differences between 'value' and 'state', deserve a whole new post ;o) ?

--DBJ

# July 11, 2010 5:49 PM

Bertrand Le Roy said:

Not sure what you mean, but by all means go for it.

# July 12, 2010 6:31 PM