Skip to content

Instantly share code, notes, and snippets.

@freddi301
Created June 17, 2016 09:35
Show Gist options
  • Save freddi301/ec9038a799593faf12b3deb074082bb3 to your computer and use it in GitHub Desktop.
Save freddi301/ec9038a799593faf12b3deb074082bb3 to your computer and use it in GitHub Desktop.
Lambda JS in Thunks
// @flow
//"use strict";
interface Evaluable {
evaluate(scope: Object): ()=> Evaluable
}
/*
{ type: Lambda ,name:String , argument: String, body: Evaluable }
*/
export class Lambda {
name: string; argument: string; body: Evaluable;
constructor(name: string, argument: string, body: Evaluable){
this.name = name;
this.argument = argument;
this.body = body;
}
evaluate(scope: Object): ()=>BoundLambda {
const self = this;
return function LambdaEvaluateThunk(): BoundLambda {
return new BoundLambda(self, scope)
}
}
}
export class BoundLambda {
lambda: Lambda; scope: any;
constructor(lambda: Lambda, scope: any){
this.lambda = lambda
this.scope = scope
}
bindArgument(parameter: Evaluable): ()=>Evaluable {
const self = this;
return function BoundLambdaBindParameterThunk() {
return self.lambda.body.evaluate(Object.assign({[self.lambda.argument]:parameter}, self.scope));
}
}
}
/*
{ type:Application, lambda: lambda, parameter: parameter }
*/
export class Application {
lambda: (Evaluable|Lambda); parameter: Evaluable;
constructor(lambda: (Lambda|Evaluable), parameter: Evaluable){
this.lambda = lambda;
this.parameter = parameter;
}
evaluate(scope: Object): ()=>Evaluable {
const self = this
return function ApplicationEvaluateThunk() {
var boundLambda: ()=>(Evaluable|BoundLambda) = self.lambda.evaluate(scope);
return function ApplicationRunRec(recBoundLambda: ()=>(Evaluable|BoundLambda)): ()=>(Evaluable|BoundLambda) {
var stepBoundLambda = recBoundLambda();
if (stepBoundLambda instanceof BoundLambda) return stepBoundLambda.bindArgument(self.parameter);
else return function ApplicationRunRecThunk() { return ApplicationRunRec(stepBoundLambda); }
}(boundLambda)
}
}
run(scope: Object): Evaluable {
return run(this.evaluate(scope||{}))
}
}
/*
{ type: reference, name: string}
*/
export class Reference {
name: string;
constructor(name: string){
this.name = name;
}
evaluate(scope: Object): ()=>Evaluable {
const self = this;
return function ReferenceEvaluateThunk() {
return scope[self.name].evaluate(scope)
}
}
}
export function run(thunk: ()=>(Evaluable)): Evaluable {
for(var ret=thunk(); typeof ret == "function"; ret=ret());
return ret
}
const I = new Lambda("I", "x", new Reference("x"))
// app1 = I(I)
const app1 = new Application(I,I)
describe("I(I)", function(){
it("should return I", function(){
expect(app1.run().lambda.name=="I")
})
})
const T = new Lambda("T", "x",
new Lambda("T/", "y", new Reference("x"))
)
const F = new Lambda("F", "x",
new Lambda("F/", "y", new Reference("y"))
)
const NOT = new Lambda("NOT", "p",
new Application(new Application(new Reference("p"), F), T)
)
// AND = a=>b=>a(b)(F)
const AND = new Lambda("AND", "a",
new Lambda("AND/", "b",
new Application(new Application(new Reference("a"), new Reference("b")), F)
)
)
// app2 = NOT(T)
const app2 = new Application(NOT, T)
describe("NOT(T)", function(){
it("should return F", function(){
expect(app2.run().lambda.name).to.equal("F")
})
})
describe("NOT(F)", function(){
it("shoudl return T", function(){
expect(new Application(NOT, F).run().lambda.name).to.equal("T")
})
})
describe("AND(T)(T)", function(){
it("should return T", function(){
expect(new Application(new Application(AND, T), T).run().lambda.name).to.equal("T")
})
})
describe("AND(F)(F)", function(){
it("should return F", function(){
expect(new Application(new Application(AND, F), F).run().lambda.name).to.equal("F")
})
})
describe("AND(T)(F)", function(){
it("should return F", function(){
expect(new Application(new Application(AND, T), F).run().lambda.name).to.equal("F")
})
})
describe("AND(F)(T)", function(){
it("should return F", function(){
expect(new Application(new Application(AND, F), T).run().lambda.name).to.equal("F")
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment