Created
April 5, 2016 13:05
-
-
Save alphaKAI/fb3bc6937f5e1a591d4dea3cc9e70c3d to your computer and use it in GitHub Desktop.
TypeScript Lazy Evalution
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Thunk { | |
public value: number; | |
public evaluated: boolean; | |
constructor(value: any) { | |
this.value = value | |
this.evaluated = false | |
} | |
} | |
class Lambda { | |
public fn: any; | |
constructor(fn: any) { | |
this.fn = fn; | |
} | |
} | |
class App { | |
public fn: any; | |
public arg: any; | |
constructor(fn: any, arg: any) { | |
this.fn = fn; | |
this.arg = arg; | |
} | |
} | |
function EvaluateX(val: any): any { | |
while (val instanceof Thunk) { | |
var v:any = val; | |
if (v.evaluated) { | |
val = val.value; | |
} else { | |
val = val.value(); | |
} | |
if (val instanceof App) { | |
val = (PeelLambda(Evaluate(val.fn)))(val.arg); | |
} | |
v.evaluated = true; | |
v.value = val; | |
} | |
return val; | |
} | |
function Evaluate(val: any): any { | |
if (val instanceof App) { | |
return Evaluate(PeelLambda(Evaluate(val.fn))(val.arg)); | |
} else if (val instanceof Thunk) { | |
return Evaluate(val.value()) | |
} else { | |
return val; | |
} | |
} | |
function PeelLambda(lam: any): any { | |
if (!(lam instanceof Lambda)) { | |
throw "type error: apply a non-lambda to a value"; | |
} | |
return lam.fn; | |
} | |
function Apply(fn: any): any { | |
return (arg: any) => new Thunk(() => new App(fn, arg)); | |
} | |
var add = new Lambda((x: number) => | |
new Lambda((y: number) => | |
new Thunk(() => | |
Evaluate(x) + Evaluate(y) | |
) | |
) | |
); | |
var sub = new Lambda((x: number) => | |
new Lambda((y: number) => | |
new Thunk(() => | |
Evaluate(x) - Evaluate(y) | |
) | |
) | |
); | |
var mul = new Lambda((x: number) => | |
new Lambda((y: number) => | |
new Thunk(() => | |
Evaluate(x) * Evaluate(y) | |
) | |
) | |
); | |
var div = new Lambda((x: number) => | |
new Lambda((y: number) => | |
new Thunk(() => | |
Evaluate(x) / Evaluate(y) | |
) | |
) | |
); | |
class Cons { | |
public car: any; | |
public cdr: any; | |
constructor(car: any, cdr: any) { | |
this.car = car; | |
this.cdr = cdr; | |
} | |
} | |
var cons = new Lambda((x) => | |
new Lambda((xs) => | |
new Thunk(() => new Cons(x, xs)) | |
) | |
); | |
class Nil {} | |
var nil = new Thunk(() => new Nil); | |
var map = new Lambda((f) => | |
new Lambda((list) => | |
new Thunk(() => { | |
var xxs = Evaluate(list); | |
if (xxs instanceof Cons) { | |
var x = xxs.car, | |
xs = xxs.cdr; | |
return Apply(Apply(cons)(Apply(f)(x)))(Apply(Apply(map)(f))(xs)); | |
} else { | |
return nil; | |
} | |
}) | |
) | |
); | |
var zero = new Thunk(() => 0); | |
var one = new Thunk(() => 1); | |
var inf = new Thunk(() => Apply(Apply(cons)(zero))(Apply(Apply(map)(Apply(add)(one)))(inf))); | |
var take = new Lambda((n) => | |
new Lambda((list) => | |
new Thunk(() => { | |
var xxs = Evaluate(list); | |
if (xxs instanceof Cons) { | |
var nval = Evaluate(n); | |
if (nval <= 0) { | |
return nil; | |
} else { | |
var x = xxs.car, | |
xs = xxs.cdr; | |
return Apply(Apply(cons)(x))(Apply(Apply(take)(Apply(Apply(sub)(n))(one)))(xs)); | |
} | |
} else { | |
return nil; | |
} | |
}) | |
) | |
); | |
class Unit {} | |
var unit = new Thunk(() => new Unit); | |
var return_ = new Lambda((x) => | |
new Thunk(() => x) | |
); | |
var print_ = new Lambda((x) => | |
new Thunk(() => { | |
console.log(Evaluate(x)); | |
return Apply(return_)(unit); | |
}) | |
); | |
var then = new Lambda((fn1) => | |
new Lambda((fn2) => | |
new Thunk(() => { | |
Evaluate(fn1); | |
Evaluate(fn2); | |
}) | |
) | |
); | |
var mapM_ = new Lambda((f) => | |
new Lambda((list) => | |
new Thunk(() => { | |
var xxs = Evaluate(list); | |
if (xxs instanceof Cons) { | |
var x = xxs.car, | |
xs = xxs.cdr; | |
return Apply(Apply(then)(Apply(f)(x)))(Apply(Apply(mapM_)(f))(xs)); | |
} else { | |
return Apply(return_)(unit); | |
} | |
}) | |
) | |
); | |
var zipWith = new Lambda((f) => | |
new Lambda((listx) => | |
new Lambda((listy) => | |
new Thunk(() => { | |
var xxs = Evaluate(listx); | |
if (xxs instanceof Cons) { | |
var yys = Evaluate(listy); | |
if (yys instanceof Cons) { | |
return Apply(Apply(cons)(Apply(Apply(f)(xxs.car))(yys.car)))(Apply(Apply(Apply(zipWith)(f))(xxs.cdr))(yys.cdr)); | |
} | |
} else { | |
return nil; | |
} | |
}) | |
) | |
) | |
); | |
var head = new Lambda((list) => | |
new Thunk(() => { | |
var xxs = Evaluate(list); | |
if (xxs instanceof Cons) { | |
return xxs.car; | |
} else { | |
throw "head: empty list"; | |
} | |
}) | |
); | |
var tail = new Lambda((list) => | |
new Thunk(() => { | |
var xxs = Evaluate(list); | |
if (xxs instanceof Cons) { | |
return xxs.cdr; | |
} else { | |
throw "tail: empty list"; | |
} | |
}) | |
); | |
////////////////// | |
var fib = new Thunk(() => | |
Apply(Apply(cons)(zero))(Apply(Apply(cons)(one))(Apply(Apply(Apply(zipWith)(add))(fib))(Apply(tail)(fib)))) | |
); | |
var twenty = new Thunk(() => 20); | |
var square = new Lambda((x) => | |
new Thunk(() => | |
Evaluate(x) * Evaluate(x) | |
) | |
); | |
Evaluate(Apply(Apply(mapM_)(print_))(Apply(Apply(take)(twenty))(inf))) | |
//Evaluate(Apply(Apply(mapM_)(print_))(Apply(Apply(map)(square))(Apply(Apply(take)(twenty))(inf)))) | |
//Evaluate(Apply(new Lambda((x) => twenty))(print_)) | |
//Evaluate(Apply(Apply(mapM_)(print_))(Apply(Apply(take)(twenty))(fib))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment