/* identity I a → a constant K a → b → a apply A (a → b) → a → b thrush T a → (a → b) → b duplication W (a → a → b) → a → b flip C (a → b → c) → b → a → c compose B (b → c) → (a → b) → a → c substitution S (a → b → c) → (a → b) → a → c chain S_³ (a → b → c) → (b → a) → b → c converge S2³ (b → c → d) → (a → b) → (a → c) → a → d psi P (b → b → c) → (a → b) → a → a → c fix-point4 Y (a → a) → a ref: https://www.willtaylor.blog/combinators-and-church-encoding-in-javscript/ */ const I = x => x const K = x => y => x const A = f => x => f (x) const T = x => f => f (x) const W = f => x => f (x) (x) const C = f => y => x => f (x) (y) const B = f => g => x => f (g (x)) const S = f => g => x => f (x) (g (x)) const S_ = f => g => x => f (g (x)) (x) const S2 = f => g => h => x => f (g (x)) (h (x)) const P = f => g => x => y => f (g (x)) (g (y)) const Y = f => (g => g (g)) (g => f (x => g (g) (x))) // validate combinators // I(1) // 1 // K(1)(2) // 1 // A(I)(1) // 1 // T(1)(I) // 1 // W(I)(1) // 1 // C(I)(1)(2) // 1 // B(I)(I)(1) // 1 // S(I)(I)(1) // 1 // S_(I)(I)(1) // 1 // S2(I)(I)(I)(1) // 1 // P(I)(I)(1)(2) // 1 // Y(I)(1) // 1 (function() { console.log('validating combinators'); console.assert(I(1) === 1, 'I failed'); console.assert(K(1)(2) === 1, 'K failed'); console.assert(A(I)(1) === 1, 'A failed'); console.assert(T(1)(I) === 1, 'T failed'); console.assert(W(I)(1) === 1, 'W failed'); // FIXME: Does this really work? console.assert(C(I)(1)(2) === 1, 'C failed'); console.assert(B(I)(I)(1) === 1, 'B failed'); console.assert(S(I)(I)(1) === 1, 'S failed'); console.assert(S_(I)(I)(1) === 1, 'S_ failed'); console.assert(S2(I)(I)(I)(1) === 1, 'S2 failed'); console.assert(P(I)(I)(1)(2) === 1, 'P failed'); console.assert(Y(I)(1) === 1, 'Y failed'); }()); // Count the number of live neighbors of a cell const countLiveNeighbors = B (A (B (A (B (A (K (A (I)))))))) (A (B (A (K (A (I)))))) const isAlive = cell => count => (cell && (count === 2 || count === 3)) || (!cell && count === 3) const rules = B (A (B (A (K (A (I)))))) (A (B (A (K (A (I)))))) const nextState = B (A (B (A (K (A (I)))))) (A (B (A (K (A (I)))))) const nextBoardState = B (A (B (A (K (A (I)))))) (A (B (A (K (A (I)))))) // validate countLiveNeighbors rules (function() { // FIXME: I think I messed up these test values, maybe? // FIXME: I also don't think this'll work given that the combinators will only grok 1 arg that is another combinator...right? console.log('validating countLiveNeighbors'); console.assert(countLiveNeighbors([[true, false, true], [false, true, false], [true, false, true]], 1, 1) === 4, 'countLiveNeighbors 1 failed'); console.assert(countLiveNeighbors([[true, false, true], [false, true, false], [true, false, true]], 0, 0) === 2, 'countLiveNeighbors 2 failed'); console.assert(countLiveNeighbors([[true, false, true], [false, true, false], [true, false, true]], 2, 2) === 4, 'countLiveNeighbors 3 failed'); console.assert(countLiveNeighbors([[true, false, true], [false, true, false], [true, false, true]], 0, 2) === 2, 'countLiveNeighbors 4 failed'); console.assert(countLiveNeighbors([[true, false, true], [false, true, false], [true, false, true]], 2, 0) === 2, 'countLiveNeighbors 5 failed'); }()); // validate isAlive rules (function() { console.log('validating isAlive'); console.assert(isAlive(true)(2) === true, 'isAlive 1 failed'); console.assert(isAlive(true)(3) === true, 'isAlive 2 failed'); console.assert(isAlive(true)(4) === false, 'isAlive 3 failed'); console.assert(isAlive(false)(3) === true, 'isAlive 4 failed'); console.assert(isAlive(false)(2) === false, 'isAlive 5 failed'); }()); // validate rules (function() { console.log('validating rules'); console.assert(rules(true)(2) === true, 'rules 1 failed'); console.assert(rules(true)(3) === true, 'rules 2 failed'); console.assert(rules(true)(4) === false, 'rules 3 failed'); console.assert(rules(false)(3) === true, 'rules 4 failed'); console.assert(rules(false)(2) === false, 'rules 5 failed'); }()); // validate nextState rules (function() { // FIXME: something is up with Bluebird I think... console.log('validating nextState'); console.assert(nextState(true)(2) === true, 'nextState 1 failed'); console.assert(nextState(true)(3) === true, 'nextState 2 failed'); console.assert(nextState(true)(4) === false, 'nextState 3 failed'); console.assert(nextState(false)(3) === true, 'nextState 4 failed'); console.assert(nextState(false)(2) === false, 'nextState 5 failed'); }()); // validate nextBoardState rules (function() { console.log('validating nextBoardState'); const board = [ [false, false, false], [true, true, true], [false, false, false] ]; const nextBoard = [ [false, true, false], [false, true, false], [false, true, false] ]; console.assert(JSON.stringify(nextBoardState(board)) === JSON.stringify(nextBoard), 'nextBoardState 1 failed'); }());