Skip to content

Instantly share code, notes, and snippets.

@alphaKAI
Created April 5, 2016 13:05
Show Gist options
  • Save alphaKAI/fb3bc6937f5e1a591d4dea3cc9e70c3d to your computer and use it in GitHub Desktop.
Save alphaKAI/fb3bc6937f5e1a591d4dea3cc9e70c3d to your computer and use it in GitHub Desktop.
TypeScript Lazy Evalution
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