I have made a lambda calculus to javascript converter and visualizer. The converter is finished, but the visualizer lacks the polish necessary for me to publish it.
Both λ
and \
works as lambda and short-hand for multiple arguments must be separated with space (eg. \x y. y
). Recursive function with an if-test must use lazy evaluation in order to work, made possible by wrapping the clauses in a function evaluated on the outside of the if (eq. if(\_.A)(\_.B)(_)
)
Because the code inludes a lot of pointless fluff, here's a small standalone evaluator. Beneath is an example. By running, it should evaluate to 120, the factorial of 5.
function λCalculus(calculus){
var nextLambda = calculus.search(/[#λ\\]/)
if(nextLambda == 0){
var delim = calculus.search(/[.:]/);
if(!~delim) throw Error("Missing body delimiter");
var head = calculus.slice(1,delim)
.split(/[^a-zA-Z0-9]+[0-9]*/);
var body = λCalculus(calculus.slice(delim+1))
var func = "#2#"
for(var i in head){
func = func.replace(/#2#/,
"function anonymous(#1#){ return #2#; }"
.replace(/#1#/,head[i]));
}
return func.replace(/#2#/,body);
} else if(nextLambda > 0){
var left = 1;
var i = nextLambda;
while(left>0&&++i<calculus.length){
if(calculus[i] == "(") left++;
else if(calculus[i] == ")") left--;
}
return calculus.slice(0,nextLambda)
+ λCalculus(calculus.slice(nextLambda,i))
+ λCalculus(calculus.slice(i));
}
return calculus;
}
// Some lambdas
var wrapper = "(λR cond zerop succ pred mult T F.@)(λx.x(x))(λc a b.c(a)(b))(λn.n(λx a b.b)(λa b.a))(λn f x. n(f)(f(x)))(λn f x. n(λg h.h(g(f)))(λu.x)(λu.u))(λa b c d.a(b(c))(d))(λx y.x)(λx y.y)"
var fac = wrapper.replace(/@/,"(λfac.fac)(R(λself n.cond(zerop(n))(λblank.succ(F))(λblank.mult(n)(R(self)(pred(n))))(0)))")
var three = "(λf x.f(f(f(x))))"
var five = "(λf x.f(f(f(f(f(x))))))"
// evaluation of (5!)
var js = λCalculus("("+fac+")"+"(λf x.f(f(f(f(f(x))))))")
function evalAsInteger(a){ return a(increment)(0); }
function increment(a){ return (a-0||0) + 1; }
console.log(js,evalAsInteger(eval(js)))