Export deferred functions.
// export functions to global;
Deferred.define();
// export to aObj
// Deferred.define(aObj);
// export specic functions
// var global = (function () { return this })();
// Deferred.define(global, ["next"]);
// full name
Deferred.next(fun);
Basic Chain
next(function () {
print("start");
}).
next(function () {
function pow (x, n) {
function _pow (n, r) {
print([n, r]);
if (n == 0) return r;
return call(_pow, n - 1, x * r);
}
return call(_pow, n, 1);
}
return call(pow, 2, 10);
}).
next(function (r) {
print([r, "end"]);
}).
error(function (e) {
alert(e);
})
function print (m) { $("#basic-code").append("\n// "+m) }
Basic Loop
This loop is slow but not blocking browsing.
loop(10, function (i) { print(i) });
function print (m) { $("#basic-loop-code").append("\n// "+m) }
Deferred Ajax
$.get("sample.html").next(function (data) {
$("#ajax-code").append("\n// "+data.length);
});
Parallel Deferred
DeferredList
print("start. gathering data.");
parallel([$.get("sample.html"), $.get("jsdeferred.js")]).
next(function (values) {
var lengths = $.map(values, function (i) { return i.length });
print(lengths.join(", "));
});
function print (m) { $("#parallel-code").append("\n// "+m) }
print("start. gathering data.");
// named parallel deferred
parallel({html: $.get("sample.html"), js: $.get("jsdeferred.js")}).
next(function (values) {
print(["html=", values.html.length, " js=", values.js.length].join(""));
});
function print (m) { $("#parallel-code2").append("\n// "+m) }
print("start. wait 3 sec.");
var list = [];
var printAndReturn = function (i) { print(i+"msec elapsed"); return i; };
list.push(wait(0).next(printAndReturn));
list.push(wait(1).next(printAndReturn));
list.push(wait(2).next(printAndReturn));
list.push(wait(3).next(printAndReturn));
parallel(list).next(function (values) {
print("Completed. values: "+values.join(", "));
});
function print (m) { $("#parallel-code1").append("\n// "+m) }
Divided Loop
next(function () {
var sum = 0;
return loop({end:100000, step:1000}, function (n, o) {
print(["Processing divided loop:n=", n, ", sum=", sum, " last?=", o.last].join(""));
for (var i = 0; i < o.step; i++) {
// print(i + n);
sum += i + n;
}
print(["sum=", sum].join(""));
return sum;
});
}).
next(function (e) {
print("Result:"+e);
print("end");
}).
error(function (e) {
print(e);
});
function print (m) { $("#loop-code").append("\n// "+m) }
loop({begin: 1, end:100, step:10}, function (n, o) {
print(["Processing divided loop:n=", n, " last?=", o.last].join(""));
for (var i = 0; i < o.step; i++) {
var j = n + i;
print(j);
}
});
function print (m) { $("#loop-code1").append("\n// "+m) }
Auto Divided Loop
function aloop (n, f) {
var i = 0;
var end = new Object;
var ret = null;
return Deferred.next(function () {
var t = (new Date()).getTime();
try {
do {
ret = f(i)
i++;
if (i >= n) throw end;
} while ((new Date()).getTime() - t < 50);
print("Devided: " + ((new Date()).getTime() - t) + "msec.");
return Deferred.call(arguments.callee);
} catch (e) {
if (e == end) {
print("End");
return ret;
} else {
throw e;
}
}
});
}
aloop(100, function (n, o) {
print(n);
for (var i = 0; i < Math.pow(n, 2); i++) {
for (var j = n; j; j--);
}
});
function print (m) { $("#aloop-code").append("\n// "+m) }
Pseudo Multi Thread
loop(10, function (n) {
print(n);
return wait(0.1);
});
loop(10, function (n) {
print(String.fromCharCode(97+n));
return wait(0.2);
});
function print (m) { $("#thread-code").append(" "+m) }
//
Shorthand
print(0);
loop(10, function (n) {
print(n);
return n;
}).
wait(1).
loop(10, function (n) {
var c = String.fromCharCode(97+n);
print(c);
return c;
}).
next(function (i) {
print("end");
}).
error(function (e) {
alert(e);
});
function print (m) { $("#shorthand-code").append(" "+m) }
//
Tiny Effects
function effect (o) {
var start = new Date().valueOf();
var curr = +o.target.style[o.name].match(/\d+/);
return next(function () {
var rate = (new Date().valueOf() - start) / o.time;
if (rate > 1) rate = 1;
o.target.style[o.name] = (curr + rate * o.value) + "px";
if (rate < 1) {
return call(arguments.callee);
}
});
}
// register function to use shorthand of chain
$.deferred.register("effect", effect);
var ele = document.getElementById("effect-code1");
effect({
target : ele,
name : "left",
value : 100,
time : 300
}).
effect({
target : ele,
name : "top",
value : 100,
time : 300
}).
next(function () {
return parallel([
effect({
target : ele,
name : "left",
value : -100,
time : 300
}),
effect({
target : ele,
name : "top",
value : -100,
time : 300
})
]);
}).
error(function (e) {
alert(e);
});
Delay Loop
loop(5, function (i, o) {
print(i);
return o.last? i : wait(1);
}).
next(function (e) {
print("end ["+e+"]");
}).
error(function (e) {
print(e);
});
function print (m) { $("#delay-loop-code1").append("\n// "+m) }
next(function (i) {
function delayloop (i) {
print(i++);
if (i < 5) {
return wait(1).next(function () {
return call(delayloop, i);
});
}
}
return call(delayloop, 0);
}).
next(function (e) {
print("end");
}).
error(function (e) {
print(e);
});
function print (m) { $("#delay-loop-code").append("\n// "+m) }
Step Run (event handling)
(double click to run this code and click to step)
var deferred = Deferred();
$("#step-run").click(function () { deferred.call() });
loop(5, function (i) {
print("running... " + i);
return deferred;
}).
next(function () {
print("completed");
});
function print (m) { $("#step-run").append("\n// "+m) }
Brainfuck interpreter
No wait but toooooooo slow :( But, but, browser will not be stopped!
function bfrun () {
var mem = $("<pre/>"), out = $("<pre/>"), button = $("#bfi-run").hide();
var sinput = $("#bfi-source").hide(), source = sinput.val();
var shtml = $("<div class='code'/>");
var selems = $.map(source.split(/\n/), function (l) {
var line = $("<div class='line'/>").appendTo(shtml);
return $.map(l.split(""), function (c) {
return $("<span/>").append(c).appendTo(line);
})
});
sinput.before(mem).before(out).before(shtml);
var pi = {
"+": function (c) {
if (!c.stack[0]) return c;
c.memory[c.pointer]++;
return c;
},
"-": function (c) {
if (!c.stack[0]) return c;
c.memory[c.pointer]--;
return c;
},
">": function (c) {
if (!c.stack[0]) return c;
c.pointer++;
c.memory[c.pointer] = (c.memory[c.pointer] || 0);
return c;
},
"<": function (c) {
if (!c.stack[0]) return c;
c.pointer--;
c.memory[c.pointer] = (c.memory[c.pointer] || 0);
return c;
},
".": function (c) {
if (!c.stack[0]) return c;
c.output.push(String.fromCharCode(c.memory[c.pointer]));
return c;
},
",": function (c) {
if (!c.stack[0]) return c;
c.memory[c.pointer] = "t";
return c;
},
"[": function (c) {
if (c.memory[c.pointer] == 0) {
c.stack.unshift(false);
} else {
c.stack.unshift(c.pos - 1);
}
return c;
},
"]": function (c) {
var s = c.stack.shift();
if (s) c.pos = s;
return c;
}
};
next(function () {
return {
pos : 0,
pointer : 0,
memory : [0],
stack : [true],
output : [],
source : source
};
}).
next(function (c) {
if (selems[c.pos]) selems[c.pos].removeClass("em");
var chr, fun;
do {
chr = c.source.charAt(c.pos);
fun = pi[chr];
c.pos++;
} while (chr.match(/[^<>,.\[\]+-]/));
var m = c.memory.concat();
m.splice(c.pointer, 1, "*"+(c.memory[c.pointer] || 0));
mem.text(m.join(", "));
out.text(c.output.join(""));
if (typeof fun == "function") {
c = fun(c);
if (c.pos < c.source.length) {
if (selems[c.pos]) selems[c.pos].addClass("em");
return call(arguments.callee, c);
} else {
return c;
}
} else {
return c;
}
}).
next(function (c) {
var reset = $("<button>Reset</button>")
sinput.after(reset);
reset.click(function () {
sinput.show();
button.show();
mem.remove();
out.remove();
shtml.remove();
reset.remove();
});
log("end");
}).
error(function (e) {
alert(e);
});
function log (m) {
// console.log(uneval(m));
}
}
callcc
like Scheme's callcc
function callcc (fun) {
var error = new Deferred();
return call(function () {
// JSDeferred passes current Deferred Object to this.
var ccdeferred = this;
// Call with current continuation (calling Deferred.next)
return fun(function (a) { ccdeferred._next.call(a); throw error });
}).
error(function (e) {
// Current Deferred chain must be stopped
if (e === error) {
return e;
} else {
throw e;
}
});
}
callcc(function (cont) {
return 10 * 10 * cont(20);
}).
next(function (val) {
print("callcc1 returns:" + val);
});
// should show "callcc1 returns:20"
var cont;
var i = 0;
callcc(function (c) {
cont = c;
return 10;
}).
next(function (val) {
print("callcc2 returns:" + val);
if (!i++) cont(20);
});
// should show "callcc2 returns:10", "callcc returns:20"
function print (m) { $("#callcc").append("\n// "+m) }
and Scheme's amb
function callcc (fun) {
var error = new Deferred();
return call(function () {
// JSDeferred passes current Deferred Object to this.
var ccdeferred = this;
// Call with current continuation (calling Deferred.next)
return fun(function (a) { ccdeferred._next.call(a); throw error });
}).
error(function (e) {
// Current Deferred chain must be stopped
if (e === error) {
return e;
} else {
throw e;
}
});
}
// http://www.sampou.org/scheme/t-y-scheme/t-y-scheme-Z-H-16.html#node_chap_14
// 上記のものをそのまま移植したもの
function amb () {
var alts = arguments;
var prevAmbFail = amb.ambFail;
return callcc(function (sk) {
return loop(alts.length, function (i) {
var alt = alts[i];
return callcc(function (fk) {
amb.ambFail = function () {
amb.ambFail = prevAmbFail;
return fk("fail");
};
return sk(alt);
});
}).
next(prevAmbFail);
});
}
amb.ambFail = function () { throw "amb tree exhausted" };
// Utility function
function amb1 (ambvars) {
var f = wait(0);
var vars = {};
for (var k in ambvars) if (ambvars.hasOwnProperty(k)) (function (name, val) {
log(name);
f = f.next(function () {
return amb.apply(this, val).next(function (i) {
vars[name] = i;
return vars;
});
});
})(k, ambvars[k]);
return f;
}
function assert (cond) {
if (!cond) throw amb();
}
// http://mayokara.info/note/view/251
Array.prototype.uniq = function(){
for (var i = 0,l = this.length; i < l; i++) {
if (this.indexOf(this[i]) < i) {
this.splice(i--, l-- && 1);
}
}
return this;
};
amb1({
baker : [1, 2, 3, 4, 5],
cooper : [1, 2, 3, 4, 5],
fletcher : [1, 2, 3, 4, 5],
miller : [1, 2, 3, 4, 5],
smith : [1, 2, 3, 4, 5]
}).
next(function (vars) { with (vars) {
log(vars);
// 簡易 distinct
assert([baker, cooper, fletcher, miller, smith].uniq().length == 5);
log("distinct passed");
assert(baker != 5);
assert(cooper != 1);
assert(fletcher != 1 && fletcher != 5);
assert(miller > cooper);
assert(Math.abs(smith - fletcher) != 1);
assert(Math.abs(fletcher - cooper) != 1);
return vars;
} }).
next(function (vars) { with (vars) {
log("solved");
log(vars);
alert(uneval(vars));
} }).
error(function (e) {
alert(e)
});
function log (m) { $("#amb").append("\n// "+ uneval(m)) }