PDA

View Full Version : Lazy JS


Trinithis
08-11-2009, 10:21 PM
Here's some code I wrote for lazy evaluation based on Scheme's take.

Syntax:

var x = lazy (function () { return expression; });
var y = force (x);


You can also do

var x = delay (function () { return expression; });
var y = force (x);


The difference between lazy and delay is that lazy will repeatedly force its answer until a promise is not met.

lazy.js

var delay, lazy, force, promise, promiseForced, promiseRunning;

(function () {

var getValue = function () {
return this.value;
};

var RUNNING = {};

var DelayThunk = function (nullaryFunc) {
this.value = nullaryFunc;
};
DelayThunk.prototype.toString = function () {
return "[object Promise]";
};
DelayThunk.prototype.force = function () {
if (promiseRunning (this)) {
throw new Error ("Circular forcing of a promise.");
}
var nullaryFunc = this.value;
this.value = RUNNING;
this.value = nullaryFunc ();
this.force = getValue;
return this.value;
};

var LazyThunk = function (nullaryFunc) {
DelayThunk.call (this, nullaryFunc);
};
LazyThunk.prototype = new DelayThunk (null);
LazyThunk.prototype.constructor = LazyThunk;
LazyThunk.prototype.force = function () {
var result = DelayThunk.prototype.force.call (this);
while (result instanceof LazyThunk) {
result = DelayThunk.prototype.force.call (result);
}
return force (result);
};

delay = function (nullaryFunc) {
return new DelayThunk (nullaryFunc);
};

lazy = function (nullaryFunc) {
return new LazyThunk (nullaryFunc);
};

force = function (expr) {
if (promise (expr)) {
return expr.force ();
}
return expr;
};

promise = function (expr) {
return expr instanceof DelayThunk;
};

promiseForced = function (expr) {
return expr.force === getValue || !promise (expr);
};

promiseRunning = function (expr) {
return expr.value === RUNNING || !promise (expr);
};

}) ();

Trinithis
08-12-2009, 04:18 AM
Infinite list example:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test</title>
</head>
<body>
<div>
<div id="out"></div>
<script type="text/javascript" src="lazy.js"></script>
<script type="text/javascript">

var print, println;

(function () {
var out = document.getElementById ("out");
print = function (x) {
out.appendChild (document.createTextNode (x));
};
println = function (x) {
print (x);
out.appendChild (document.createElement ("br"));
};
}) ();

/*************************************************************************************/

function List (value, next) {
this.value = value;
this.next = next;
}

List.prototype = {

constructor: List

, print: function () {
if (this === NULL) {
print ("[]");
}
else {
print (this.head ());
println (":");
var self = this;
setTimeout (function () {
self.tail ().print ();
}, 1);
}
}

, head: function () {
return this.value;
}

, tail: function () {
return force (this.next);
}
};

var NULL = new List (undefined, null);

function cons (x, xs) {
return new List (x, xs);
}

/*************************************************************************************/

function zipWith (f, xs, ys) {
if (xs === null || ys === null) {
return NULL;
}
var fxy = f (xs.head (), ys.head ());
return cons (fxy, lazy (function () { return zipWith (f, xs.tail (), ys.tail ()); }));
}

function add (x, y) {
return x + y;
}

var fibs = cons (0, lazy (function () {
return cons (1, lazy (function () {
return zipWith (add, fibs, fibs.tail ());
}));
}));

fibs.print ();

</script>
</div>
</body>
</html>