Skip to content

Commit 2c6d88b

Browse files
authored
Merge pull request #44 from JohanWiltink/main
all my fixes from the past week
2 parents b267976 + 7c8a6f7 commit 2c6d88b

File tree

10 files changed

+341
-69
lines changed

10 files changed

+341
-69
lines changed

TODO.md

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/lambda-calculus.js

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class Tuple {
9595
function Primitive(v) { return new Tuple(new V( "<primitive>" ), new Env([[ "<primitive>" , function*() { while ( true ) yield v; } () ]])); }
9696

9797
const primitives = new Env;
98-
primitives.setThunk( "trace", new Tuple( Primitive( function(v) { console.log(String(v.term)); return v; } ), new Env ) );
98+
primitives.setThunk( "trace", new Tuple( Primitive( function(v) { console.info(String(v.term)); return v; } ), new Env ) );
9999

100100
const Y = new L("f",new A(new L("x",new A(new V("f"),new A(new V("x"),new V("x")))),new L("x",new A(new V("f"),new A(new V("x"),new V("x"))))));
101101

@@ -176,6 +176,7 @@ function parseWith(cfg={}) {
176176
if ( purity === "Let" )
177177
return Array.from(FV).reduce( (tm,nm) => {
178178
if ( env.has(nm) ) {
179+
if ( config.verbosity >= "Verbose" ) console.debug(` using ${ nm } = ${ env.getValue(nm) }`);
179180
tm.env.set( nm, env.get(nm) );
180181
return tm;
181182
} else {
@@ -185,16 +186,17 @@ function parseWith(cfg={}) {
185186
} , new Tuple( term, new Env ) );
186187
else if ( purity==="LetRec" )
187188
return Array.from(FV).reduce( (tm,nm) => {
188-
if ( nm === name )
189-
return tm;
190-
else if ( env.has(nm) ) {
191-
tm.env.set( nm, env.get(nm) );
192-
return tm;
193-
} else {
194-
if ( verbosity >= "Concise" ) console.error(`parse: while defining ${ name } = ${ term }`);
195-
throw new ReferenceError(`undefined free variable ${ nm }`);
196-
}
197-
} , new Tuple( FV.has(name) ? new A(Y,new L(name,term)) : term , new Env ) );
189+
if ( nm === name )
190+
return tm;
191+
else if ( env.has(nm) ) {
192+
if ( config.verbosity >= "Verbose" ) console.debug(` using ${ nm } = ${ env.getValue(nm) }`);
193+
tm.env.set( nm, env.get(nm) );
194+
return tm;
195+
} else {
196+
if ( verbosity >= "Concise" ) console.error(`parse: while defining ${ name } = ${ term }`);
197+
throw new ReferenceError(`undefined free variable ${ nm }`);
198+
}
199+
} , new Tuple( FV.has(name) ? new A(Y,new L(name,term)) : term , new Env ) );
198200
else if ( purity==="PureLC" )
199201
if ( FV.size ) {
200202
if ( verbosity >= "Concise" ) console.error(`parse: while defining ${ name } = ${ term }`);
@@ -300,6 +302,8 @@ function parseWith(cfg={}) {
300302
const [i,r] = defn(0);
301303
if ( i===code.length ) {
302304
const [name,term] = r;
305+
if ( config.verbosity >= "Loquacious" )
306+
console.debug(`compiled ${ name }${ config.verbosity >= "Verbose" ? ` = ${ term }` : "" }`);
303307
return env.setThunk( name, wrap(name,term));
304308
} else
305309
error(i,"defn: incomplete parse");
@@ -328,16 +332,14 @@ function compileWith(cfg={}) {
328332
// Top level call, term :: Tuple
329333
function evalLC(term) {
330334

331-
// builds function to return to user (representing an abstraction awaiting input)
335+
// builds function to return to user ( representing an abstraction awaiting input )
332336
function awaitArg(term, stack, env) {
333-
334-
// callback function which will apply the input to the term
337+
// callback function which will evaluate term.body in an env with the input
335338
function result(arg) {
336339
let argEnv;
337-
if ( arg.term && arg.env ) ({ term: arg, env: argEnv } = arg); // If callback is passed another callback, or a term
340+
if ( arg.term && arg.env ) ({ term: arg, env: argEnv } = arg); // if callback is passed another callback, or a term
338341
const termVal = new Tuple( typeof arg !== 'number' ? arg : fromInt(arg) , new Env(argEnv) );
339-
const newEnv = new Env(env).setThunk(term.name, termVal);
340-
return runEval(new Tuple(term.body, newEnv), stack);
342+
return runEval( new Tuple(term.body, new Env(env).setThunk(term.name, termVal)), stack );
341343
}
342344
return Object.assign( result, {term,env} );
343345
}
@@ -411,29 +413,17 @@ function evalLC(term) {
411413
}
412414

413415
// Print an error, with stack trace according to verbosity level
414-
function printStackTrace(error, term, stack) {
415-
if (config.verbosity == "Calm") return; // No error message for Calm
416-
else if (config.verbosity == "Concise")
417-
console.error(`${error} inside definition of <code>${term.defName}</code>`);
418-
else if (config.verbosity == "Loquacious") {
419-
// Loquacious will provide a stack trace localised to the definition
420-
if (stack.length == 0 || stack[stack.length-1] == term.defName)
421-
console.error(`${error} inside definition of <code>${term.defName}</code>`);
422-
else {
423-
const localStack = stack.slice(stack.indexOf(term.defName)+1).reverse();
424-
console.error(`${error} inside definition of <code>${term.defName}</code>
425-
${localStack.map(v=>'\twhile evaluating <code>' + v + '</code>').join('\n')}`)
426-
}
427-
} else if (config.verbosity == "Verbose") {
428-
// Verbose will provide a full stack trace
429-
if (stack.length == 0)
430-
console.error(`${error} inside definition of <code>${term.defName}</code>`);
431-
else {
432-
const localStack = stack.reverse();
433-
console.error(`${error} inside definition of <code>${term.defName}</code>
434-
${localStack.map(v=>'\twhile evaluating <code>' + v + '</code>').join('\n')}`)
435-
}
436-
}
416+
function printStackTrace(error, term, stack) { console.log("printStackTrace",config.verbosity)
417+
if ( config.verbosity >= "Concise" )
418+
console.error(`${ error } inside definition of <code>${ term.defName }</code>`);
419+
420+
const stackCutoff = config.verbosity < "Verbose" && stack[stack.length-1] == term.defName ? stack.indexOf(term.defName) + 1 : 0 ;
421+
422+
if ( config.verbosity >= "Loquacious" )
423+
console.error( stack.slice(stackCutoff).reverse().map( v => `\twhile evaluating <code>${ v }</code>`).join('\n') );
424+
425+
if ( config.verbosity >= "Verbose" )
426+
console.error( stack.slice().reverse().map( v => `\twhile evaluating <code>${ v }</code>`).join('\n') );
437427
}
438428

439429
Object.defineProperty( Function.prototype, "valueOf", { value: function valueOf() { return toInt(this); } } );

tests/basics-binary-scott/test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const {assert} = chai;
44
const LC = require("../../src/lambda-calculus.js");
55
LC.config.purity = "LetRec";
66
LC.config.numEncoding = "BinaryScott";
7-
LC.config.verbosity = "Concise";
87

98
const solution = LC.compile();
109
const fromInt = LC.fromIntWith(LC.config);

tests/basics-church/test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const {assert} = chai;
44
const LC = require("../../src/lambda-calculus.js");
55
LC.config.purity = "LetRec";
66
LC.config.numEncoding = "Church";
7-
LC.config.verbosity = "Concise";
87

98
const solution = LC.compile();
109
const fromInt = LC.fromIntWith(LC.config);

tests/multiply/solution.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
multiply = \ m n . n (m s ) z

tests/multiply/test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const {assert} = require("chai");
2+
3+
const LC = require("../../src/lambda-calculus.js");
4+
LC.config.purity = "LetRec";
5+
LC.config.numEncoding = "Church";
6+
// LC.config.verbosity = "Concise"; // reinstate for production
7+
8+
const {multiply} = LC.compile();
9+
10+
describe("Multiply",function(){
11+
it("example tests",()=>{
12+
assert.equal( multiply(7)(7), 49 );
13+
assert.equal( multiply(11)(11), 121 );
14+
});
15+
it("random tests",()=>{
16+
const rnd = (m,n=0) => Math.random() * (n-m) + m | 0 ;
17+
for ( let i=1; i<=100; i++ ) {
18+
const m = rnd(i), n = rnd(i);
19+
assert.equal( multiply(m)(n), m*n );
20+
}
21+
});
22+
});

tests/prime-sieve/test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const {assert} = chai;
55
const LC = require("../../src/lambda-calculus.js");
66
LC.config.purity = "LetRec";
77
LC.config.numEncoding = "BinaryScott";
8-
LC.config.verbosity = "Concise";
98

109
const {primes} = LC.compile();
1110
const toInt = LC.toIntWith(LC.config);

tests/run-tests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const examples = [ "basics-binary-scott"
1010
, "is-prime"
1111
, "is-prime-scott"
1212
, "prime-sieve"
13+
, "scott-lists"
14+
, "multiply"
1315
];
1416

1517
try {

0 commit comments

Comments
 (0)