Created
June 17, 2016 09:35
-
-
Save freddi301/ec9038a799593faf12b3deb074082bb3 to your computer and use it in GitHub Desktop.
Lambda JS in Thunks
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
// @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