Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions example/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@ chaiConfig.truncateThreshold = 0;
import * as LC from "@codewars/lambda-calculus";
import { solution } from "./files.js"; // /workspace/files.js

LC.config.purity = "Let";
LC.config.numEncoding = "Church";
const toInt = LC.toIntWith(LC.config);
LC.configure({ purity: "Let", numEncoding: "Church" });
const { counter } = LC.compile(solution());

const T = t => _ => t;
const F = _ => f => f;

describe("counter", () => {
it("fixed tests", () => {
assert.strictEqual(toInt(counter(T)(T)(T)(F)), 3);
assert.strictEqual(toInt(counter(T)(F)), 1);
assert.strictEqual(toInt(counter(T)(T)(T)(T)(T)(T)(T)(F)), 7);
assert.equal( counter(T)(T)(T)(F), 3);
assert.equal( counter(T)(F), 1);
assert.equal( counter(T)(T)(T)(T)(T)(T)(T)(F), 7);
});
});
419 changes: 200 additions & 219 deletions src/lambda-calculus.js

Large diffs are not rendered by default.

173 changes: 73 additions & 100 deletions tests/basics-binary-scott/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import {readFileSync} from "fs";
import {assert} from "chai";

import * as LC from "../../src/lambda-calculus.js";
LC.config.purity = "LetRec";
LC.config.numEncoding = "BinaryScott";
LC.configure({ purity: "LetRec", numEncoding: "BinaryScott" });

const solutionText = readFileSync(new URL("./solution.txt", import.meta.url), {encoding: "utf8"});
const solution = LC.compile(solutionText);
const fromInt = LC.fromIntWith(LC.config);
const toInt = LC.toIntWith(LC.config);
const {fromInt,toInt} = LC;

const {False,True,not,and,or,xor,implies} = solution;
const {LT,EQ,GT,compare,lt,le,eq,ge,gt} = solution;
Expand All @@ -27,220 +25,196 @@ const refGCD = m => n => n ? refGCD(n)(m%n) : m ;
describe("Binary Scott tests",function(){
this.timeout(0);
it("enumeration",()=>{
LC.configure({ purity: "LetRec", numEncoding: "BinaryScott" });
const one = succ(zero)
const two = succ(one)
const three = succ(two)
const four = succ(three)
const five = succ(four)
assert.strictEqual( toString(zero), "$" );
assert.strictEqual( toString(one), "1$" );
assert.strictEqual( toString(two), "01$" );
assert.strictEqual( toString(three), "11$" );
assert.strictEqual( toString(four), "001$" );
assert.strictEqual( toString(five), "101$" );
assert.strictEqual( toString(five), "101$" );
assert.strictEqual( toString(pred(five)), "001$" );
assert.strictEqual( toString(unpad(pred(pred(five)))), "11$" );
assert.strictEqual( toString(unpad(pred(pred(pred(five))))), "01$" );
assert.strictEqual( toString(unpad(pred(pred(pred(pred(five)))))), "1$" );
assert.strictEqual( toString(unpad(pred(pred(pred(pred(pred(five))))))), "$" );
assert.equal( toString(zero), "$" );
assert.equal( toString(one), "1$" );
assert.equal( toString(two), "01$" );
assert.equal( toString(three), "11$" );
assert.equal( toString(four), "001$" );
assert.equal( toString(five), "101$" );
assert.equal( toString(five), "101$" );
assert.equal( toString(pred(five)), "001$" );
assert.equal( toString(unpad(pred(pred(five)))), "11$" );
assert.equal( toString(unpad(pred(pred(pred(five))))), "01$" );
assert.equal( toString(unpad(pred(pred(pred(pred(five)))))), "1$" );
assert.equal( toString(unpad(pred(pred(pred(pred(pred(five))))))), "$" );
});
it("successor",()=>{
let n = zero;
let n = 0;
for ( let i=1; i<=100; i++ ) {
n = succ (n);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ i } <- ${ toString(n) }`);
assert.strictEqual( toInt(n), i );
assert.equal( n, i );
}
});
it("predecessor",()=>{
let n = fromInt(100);
let n = 100;
for ( let i=100; i--; ) {
n = pred (n);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ i } <- ${ toString(n) }`);
assert.strictEqual( toInt(n), i );
assert.equal( n, i );
}
});
it("predecessor robustness",()=>{
if ( LC.config.verbosity >= "Loquacious" ) console.log(`pred 01$ -> 1$`);
assert.strictEqual( toString( pred ( fromInt(2) ) ), "1$" );
if ( LC.config.verbosity >= "Loquacious" ) console.log(`pred $ -> $`);
assert.strictEqual( toString( pred ( end => even => odd => end ) ), "$" );
if ( LC.config.verbosity >= "Loquacious" ) console.log(`pred 0$ -> $`);
assert.strictEqual( toString( pred ( end => even => odd => even (
end => even => odd => end ) ) ), "$" );
if ( LC.config.verbosity >= "Loquacious" ) console.log(`pred 00$ -> $`);
assert.strictEqual( toString( pred ( end => even => odd => even (
end => even => odd => even (
end => even => odd => end ) ) ) ), "$" );
assert.equal( toString( pred ( 2 ) ), "1$" );
assert.equal( toString( pred ( end => even => odd => end ) ), "$" );
assert.equal( toString( pred ( end => even => odd => even (
end => even => odd => end ) ) ), "$" );
assert.equal( toString( pred ( end => even => odd => even (
end => even => odd => even (
end => even => odd => end ) ) ) ), "$" );
});
it("ordering",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`compare ${ m } ${ n }`);
assert.strictEqual( compare (fromInt(m)) (fromInt(n)) ("-1") ("0") ("1"), String(Number(m>n) - Number(m<n)) );
assert.equal( compare (fromInt(m)) (fromInt(n)) ("-1") ("0") ("1"), String(Number(m>n) - Number(m<n)) );
}
});
it("comparison",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`compare ${ m } ${ n }`);
assert.strictEqual( lt (fromInt(m)) (fromInt(n)) (false)(true), m < n );
assert.strictEqual( le (fromInt(m)) (fromInt(n)) (false)(true), m <= n );
assert.strictEqual( eq (fromInt(m)) (fromInt(n)) (false)(true), m == n );
assert.strictEqual( ge (fromInt(m)) (fromInt(n)) (false)(true), m >= n );
assert.strictEqual( gt (fromInt(m)) (fromInt(n)) (false)(true), m > n );
assert.strictEqual( eq (fromInt(m)) (fromInt(m)) (false)(true), true );
assert.equal( lt (fromInt(m)) (fromInt(n)) (false)(true), m < n );
assert.equal( le (fromInt(m)) (fromInt(n)) (false)(true), m <= n );
assert.equal( eq (fromInt(m)) (fromInt(n)) (false)(true), m == n );
assert.equal( ge (fromInt(m)) (fromInt(n)) (false)(true), m >= n );
assert.equal( gt (fromInt(m)) (fromInt(n)) (false)(true), m > n );
assert.equal( eq (fromInt(m)) (fromInt(m)) (false)(true), true );
}
});
it("addition",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ m } + ${ n } = ${ m+n }`);
assert.strictEqual( toInt( plus (fromInt(m)) (fromInt(n)) ), m + n );
assert.equal( plus (m) (n), m + n );
}
});
it("multiplication",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ m } * ${ n } = ${ m*n }`);
assert.strictEqual( toInt( times (fromInt(m)) (fromInt(n)) ), m * n );
assert.equal( times (m) (n), m * n );
}
});
it("subtraction",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`subtract ${ m } ${ n }`);
assert.strictEqual( toInt( minus (fromInt(m)) (fromInt(n)) ), Math.max( 0, m - n ) );
assert.strictEqual( toInt( minus (fromInt(n)) (fromInt(m)) ), Math.max( 0, n - m ) );
assert.equal( minus (m) (n), Math.max( 0, m - n ) );
assert.equal( minus (n) (m), Math.max( 0, n - m ) );
}
});
it("division",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`division ${ m } ${ n }`);
assert.deepEqual( toPair( divMod (fromInt(m)) (fromInt(n||1)) ).map(toInt), [ m/(n||1)|0, m%(n||1) ] );
assert.deepEqual( toPair( divMod (fromInt(n)) (fromInt(m||1)) ).map(toInt), [ n/(m||1)|0, n%(m||1) ] );
assert.deepEqual( toPair( divMod (m) (n||1) ).map(toInt), [ m/(n||1)|0, m%(n||1) ] );
assert.deepEqual( toPair( divMod (n) (m||1) ).map(toInt), [ n/(m||1)|0, n%(m||1) ] );
}
});
it("exponentiation",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i), n = rnd(i%10);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ m } ** ${ n } = ${ m**n }`);
assert.strictEqual( toInt( pow (fromInt(m)) (fromInt(n)) ), m ** n );
assert.equal( pow (m) (n), m ** n );
}
});
it("greatest common divisor",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i), n = rnd(i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`gcd ${ m } ${ n } = ${ refGCD(m)(n) }`);
assert.strictEqual( toInt( gcd (fromInt(m)) (fromInt(n)) ), refGCD(m)(n) );
assert.equal( gcd (m) (n), refGCD(m)(n) );
}
});
it("least common multiple",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i), n = rnd(i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`lcm ${ m } ${ n } = ${ m/(refGCD(m)(n)||1)*n }`);
assert.strictEqual( toInt( lcm (fromInt(m)) (fromInt(n)) ), m / (refGCD(m)(n)||1) * n );
assert.equal( lcm (m) (n), m / (refGCD(m)(n)||1) * n );
}
});
it("minimum",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`min ${ m } ${ n } = ${ Math.min(m,n) }`);
assert.strictEqual( toInt( min (fromInt(m)) (fromInt(n)) ), Math.min(m,n) );
assert.equal( min (m) (n), Math.min(m,n) );
}
});
it("maximum",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`max ${ m } + ${ n } = ${ Math.max(m,n) }`);
assert.strictEqual( toInt( max (fromInt(m)) (fromInt(n)) ), Math.max(m,n) );
assert.equal( max (m) (n), Math.max(m,n) );
}
});
it("shifting bits",()=>{
for ( let i=1; i<=100; i++ ) {
const n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`shift ${ n }`);
assert.strictEqual( toInt( shiftL (fromInt(n)) ), n >> 1 );
assert.strictEqual( toInt( shiftR0 (fromInt(n)) ), n << 1 );
assert.strictEqual( toInt( shiftR1 (fromInt(n)) ), n << 1 | 1 );
assert.equal( shiftL (n), n >> 1 );
assert.equal( shiftR0 (n), n << 1 );
assert.equal( shiftR1 (n), n << 1 | 1 );
}
});
it("zero padding",()=>{
for ( let i=1; i<=100; i++ ) {
const n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`isPadded ${ n }`);
assert.strictEqual( isPadded (fromInt(n)) (false)(true), false );
assert.strictEqual( isPadded (pad(fromInt(n))) (false)(true), true );
assert.strictEqual( isPadded (pad(pad(fromInt(n)))) (false)(true), true );
assert.strictEqual( isPadded (pad(pad(pad(fromInt(n))))) (false)(true), true );
assert.equal( isPadded (n) (false)(true), false );
assert.equal( isPadded (pad(n)) (false)(true), true );
assert.equal( isPadded (pad(pad(n))) (false)(true), true );
assert.equal( isPadded (pad(pad(pad(n)))) (false)(true), true );
}
});
it("bitwise and",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ m } & ${ n } = ${ m&n }`);
assert.strictEqual( toInt( bitAnd (fromInt(m)) (fromInt(n)) ), m & n );
assert.equal( bitAnd (m) (n), m & n );
}
});
it("bitwise or",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ m } | ${ n } = ${ m|n }`);
assert.strictEqual( toInt( bitOr (fromInt(m)) (fromInt(n)) ), m | n );
assert.equal( bitOr (m) (n), m | n );
}
});
it("bitwise exclusive or",()=>{
for ( let i=1; i<=100; i++ ) {
const m = rnd(i*i), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`${ m } ^ ${ n } = ${ m^n }`);
assert.strictEqual( toInt( bitXor (fromInt(m)) (fromInt(n)) ), m ^ n );
assert.equal( bitXor (m) (n), m ^ n );
}
});
it("testing bits",()=>{
for ( let i=1; i<=100; i++ ) {
const j = rnd(i%32), n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`testBit ${ j } ${ n } = ${ Boolean( n & 1<<j ) }`);
assert.strictEqual( testBit (fromInt(j)) (fromInt(n)) (false)(true), Boolean( n & 1<<j ) ); // JS restricted to 32-bit
assert.equal( testBit (j) (n) (false)(true), Boolean( n & 1<<j ) ); // JS restricted to 32-bit
}
});
it("setting bits",()=>{
for ( let i=1; i<=100; i++ ) {
const j = rnd(i%32);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`bit ${ j } = ${ 1<<j }`);
assert.strictEqual( toInt( bit (fromInt(j)) ), 1<<j ); // JS restricted to 32-bit
assert.equal( bit (j), 1<<j ); // JS restricted to 32-bit
}
});
it("population count",()=>{
const refPopCount = n => n && 1 + refPopCount(n & n-1) ;
for ( let i=1; i<=100; i++ ) {
const n = rnd(i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`popCount ${ n } = ${ refPopCount(n) }`);
assert.strictEqual( toInt( popCount (fromInt(n)) ), refPopCount(n) ); // JS restricted to 32-bit
assert.equal( popCount (n), refPopCount(n) ); // JS restricted to 32-bit
}
});
it("logical not",()=>{
assert.strictEqual( not(False) (false)(true), true );
assert.strictEqual( not(True) (false)(true), false );
assert.equal( not(False) (false)(true), true );
assert.equal( not(True) (false)(true), false );
});
it("logical and",()=>{
assert.strictEqual( and(False)(False) (false)(true), false );
assert.strictEqual( and(False)(True) (false)(true), false );
assert.strictEqual( and(True) (False) (false)(true), false );
assert.strictEqual( and(True) (True) (false)(true), true );
assert.equal( and(False)(False) (false)(true), false );
assert.equal( and(False)(True) (false)(true), false );
assert.equal( and(True) (False) (false)(true), false );
assert.equal( and(True) (True) (false)(true), true );
});
it("logical or",()=>{
assert.strictEqual( or(False)(False) (false)(true), false );
assert.strictEqual( or(False)(True) (false)(true), true );
assert.strictEqual( or(True) (False) (false)(true), true );
assert.strictEqual( or(True) (True) (false)(true), true );
assert.equal( or(False)(False) (false)(true), false );
assert.equal( or(False)(True) (false)(true), true );
assert.equal( or(True) (False) (false)(true), true );
assert.equal( or(True) (True) (false)(true), true );
});
it("logical exclusive or",()=>{
assert.strictEqual( xor(False)(False) (false)(true), false );
assert.strictEqual( xor(False)(True) (false)(true), true );
assert.strictEqual( xor(True) (False) (false)(true), true );
assert.strictEqual( xor(True) (True) (false)(true), false );
assert.equal( xor(False)(False) (false)(true), false );
assert.equal( xor(False)(True) (false)(true), true );
assert.equal( xor(True) (False) (false)(true), true );
assert.equal( xor(True) (True) (false)(true), false );
});
it("logical implies",()=>{
assert.strictEqual( implies(False)(False) (false)(true), true );
Expand All @@ -251,9 +225,8 @@ describe("Binary Scott tests",function(){
it("parity",()=>{
for ( let i=1; i<=100; i++ ) {
const n = rnd(i*i*i);
if ( LC.config.verbosity >= "Loquacious" ) console.log(`parity ${ n }`);
assert.strictEqual( odd (fromInt(n)) (false)(true), Boolean(n&1) );
assert.strictEqual( even (fromInt(n)) (false)(true), ! (n&1) );
assert.equal( odd (fromInt(n)) (false)(true), Boolean(n&1) );
assert.equal( even (fromInt(n)) (false)(true), ! (n&1) );
}
});
});
29 changes: 13 additions & 16 deletions tests/basics-church/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,39 @@ import {readFileSync} from "fs";
import {assert} from "chai";

import * as LC from "../../src/lambda-calculus.js";
LC.config.purity = "LetRec";
LC.config.numEncoding = "Church";
LC.configure({ purity: "LetRec", numEncoding: "Church" });

const solutionText = readFileSync(new URL("./solution.txt", import.meta.url), {encoding: "utf8"});
const solution = LC.compile(solutionText);
const fromInt = LC.fromIntWith(LC.config);
const toInt = LC.toIntWith(LC.config);
const { fromInt, toInt } = LC;

const {B,C,I,KI,M,S,T,V,W,Y,Z} = solution;
const {True,False,not,and,or,xor,implies} = solution;
const {lt,le,eq,ge,gt} = solution;
const {zero,succ,pred,isZero} = solution;
const {plus,times,pow,minus} = solution;

const toPair = xy => [ fst(xy), snd(xy) ] ;

const rnd = (m,n=0) => Math.random() * (n-m) + m | 0 ;

describe("Church tests",function(){
this.timeout(0);
it("fixed tests",()=>{
LC.configure({ purity: "LetRec", numEncoding: "Church" });
const one = succ(zero);
const two = succ(one);
const three = succ(two);
const four = succ(three);
const five = succ(four);
assert.strictEqual( toInt(zero), 0 );
assert.strictEqual( toInt(one), 1 );
assert.strictEqual( toInt(two), 2 );
assert.strictEqual( toInt(three), 3 );
assert.strictEqual( toInt(four), 4 );
assert.strictEqual( toInt(five), 5 );
assert.equal( zero, 0 );
assert.equal( one, 1 );
assert.equal( two, 2 );
assert.equal( three, 3 );
assert.equal( four, 4 );
assert.equal( five, 5 );
const n = 1e3;
assert.strictEqual( toInt(I(fromInt(n))), n );
assert.strictEqual( toInt(times(fromInt(1e2))(fromInt(1e1))), 1e3 );
assert.strictEqual( toInt(pow(fromInt(10))(fromInt(3))), 1e3 );
assert.strictEqual( toInt(pred(pow(fromInt(10))(fromInt(3)))), 1e3-1 );
assert.equal( I(fromInt(n)), n );
assert.equal( times(1e2)(1e1), 1e3 );
assert.equal( pow(10)(3), 1e3 );
assert.equal( pred(pow(10)(3)), 1e3-1 );
});
});
Loading