diff options
Diffstat (limited to 'repl.ts')
-rw-r--r-- | repl.ts | 106 |
1 files changed, 106 insertions, 0 deletions
@@ -0,0 +1,106 @@ +const peggy = require("./parser.js"); + +const isVariable = (ast: any) => typeof ast === "string"; +const isApplication = (ast: any) => + typeof ast === "object" && "application" in ast; +const isAbstraction = (ast: any) => + typeof ast === "object" && "abstraction" in ast; + +const emitCode = (ast: any) => { + if (isVariable(ast)) { + return ast; + } + + if (isApplication(ast)) { + const { application } = ast; + const { left, right } = application; + return `( ${emitCode(left)} ${emitCode(right)} )`; + } + + const { abstraction } = ast; + const { param, body } = abstraction; + + return `(λ ${emitCode(param)} . ${emitCode(body)})`; +}; + +const substitute = (param: string, term: any, result: any) => { + if (isVariable(term)) { + if (term === param) { + return result; + } + return term; + } + + if (isApplication(term)) { + const { application } = term; + const { left, right } = application; + + return { + application: { + left: substitute(param, left, result), + right: substitute(param, right, result), + }, + }; + } + + const { abstraction } = term; + const { body } = abstraction; + return { + abstraction: { + param: abstraction.param, + body: substitute(param, body, result), + }, + }; +}; + +const betaReduce = (ast: any) => { + if (isVariable(ast)) { + return ast; + } + + if (isApplication(ast)) { + const { application } = ast; + const { left, right } = application; + + if (isAbstraction(left)) { + const { abstraction } = left; + const { param } = abstraction; + + return substitute(param, right); + } + + return { + application: { + left: betaReduce(left), + right: betaReduce(right), + }, + }; + } + + // it's an abstraction + const { abstraction } = ast; + const { param, body } = abstraction; + return { param: betaReduce(param), body: betaReduce(body) }; +}; + +const evaluate = (lambdaTerm: string) => { + const ast = peggy.parse(lambdaTerm); + + const fullBetaReduction = betaReduce(ast); + return emitCode(fullBetaReduction); +}; + +const doRepl = async () => { + const prompt = ">>> "; + process.stdout.write(prompt); + + for await (const line of console) { + const result = evaluate(line); + console.log(result); + break; + } + + await doRepl(); +}; + +await doRepl(); |