diff --git a/nothing-helper.js b/nothing-helper.js index d54700c..618a959 100644 --- a/nothing-helper.js +++ b/nothing-helper.js @@ -1,4 +1,53 @@ -module.exports = { - to_int: (f) => f(n => n+1)(0), - to_boolean: (f) => f(true)(false), +const nothing = require('./nothing.js'); + +const charset = '0123456789BFiuz'; +const from_int = (n) => { + let f = nothing.ZERO; + for (let _ = 0; _ < n; _++) f = nothing.INC(f); + return f; +}; +const to_int = (f) => nothing.TIMES(f)(i => i+1)(0); +const from_bool = (b) => b ? nothing.TRUE : nothing.FALSE; +const to_bool = (f) => f(true)(false); +const to_array = (l) => { + let a = []; + + while (!to_bool(nothing.IS_EMPTY(l))) { + a.push(nothing.FIRST(l)); + l = nothing.REST(l); + } + + return a; +}; +const from_array = (a) => { + let l = nothing.EMPTY; + + while (a.length) l = nothing.UNSHIFT(l)(a.pop()); + + return l; +}; +const to_char = (c) => charset[to_int(c)]; +const from_char = (c) => from_int(charset.indexOf(c)); +const to_string = (s) => to_array(s).map(to_char).join(''); +const from_string = (s) => from_array(s.split('').map(from_char)); +const representation_of = (v) => { + if (typeof v == "number") return from_int(v); + if (typeof v == "boolean") return from_bool(v); + if (typeof v == "string") return from_string(v); + if (Array.isArray(v)) return from_array(v.map(representation_of)); + throw Error(`Oops, I don’t know how represent this: ${v}`); +}; +const zip = (a, b) => a.map((e, i) => [e, b[i]]); +const check_represent = function(r, v) { + if (typeof v == "number") return to_int(r) == v; + if (typeof v == "boolean") return to_bool(r) == v; + if (typeof v == "string") { console.log("checking ", to_array(r).map(to_int), " against ", v); return to_string(r) == v; } + if (Array.isArray(v)) { + let a = to_array(r); + return a.length == v.length && zip(a, v).every(([r, v]) => check_represent(r,v)); + } + throw Error(`Oops, I don’t know how check this: ${v}`); +}; +module.exports = { + to_string, to_array, representation_of, check_represent, to_int, to_char }; diff --git a/nothing.js b/nothing.js index da1b579..e595508 100644 --- a/nothing.js +++ b/nothing.js @@ -18,37 +18,55 @@ const NOT = b => IF(b)(FALSE)(TRUE); const AND = a => b => IF(a)(IF(b)(TRUE)(FALSE))(FALSE); const OR = a => b => IF(a)(TRUE)(IF(b)(TRUE)(FALSE)); const IS_ZERO = n => n(x => FALSE)(TRUE); -const IS_LEQ = n => m => IS_ZERO(SUBTRACT(n)(m)); // we only have positive ints +const IS_LEQ = n => m => IS_ZERO(SUB(n)(m)); // we only have positive ints const IS_EQ = n => m => AND(IS_LEQ(n)(m))(IS_LEQ(m)(n)); // this is stupid // time to get recursive! const Y = f => (x => f(x(x)))(x => f(x(x))); // lazy recursion const Z = f => (x => f(_ => x(x)(_)))(x => f(_ => x(x)(_))); // eager recursion const FACT = Z(f => n => IF(IS_ZERO(n))(ONE)(_ => MULT(n)(f(DEC(n)))(_))); -const DIV = null; -const MOD = null; -const PAIR = null; -const LEFT = null; -const RIGHT = null; -const EMPTY = null; -const UNSHIFT = null; -const IS_EMPTY = null; -const FIRST = null; -const REST = null; -const INJECT = null; -const FOLD = null; -const MAP = null; -const RANGE = null; -const SUM = null; -const PROD = null; -const CONCAT = null; -const PUSH = null; -const REVERSE = null; -const INC_ALL = null; -const DOUBLE_ALL = null; -const TO_DIGITS = null; -const TO_STRING = null; -const FIZZBUZZ = null; +const DIV = Z(f => n => m => IF(IS_LEQ(m)(n))(_ => INC(f(SUB(n)(m))(m))(_))(ZERO)); +const MOD = Z(f => n => m => IF(IS_LEQ(m)(n))(_ => f(SUB(n)(m))(m)(_))(m)); +const PAIR = x => y => f => f(x)(y); +const LEFT = p => p(x => y => x); +const RIGHT = p => p (x => y => y); +const EMPTY = PAIR(TRUE)(TRUE); +const UNSHIFT = l => x => PAIR(FALSE)(PAIR(x)(l)); +const IS_EMPTY = LEFT; +const FIRST = l => LEFT(RIGHT(l)); +const REST = l => RIGHT(RIGHT(l)); +const INJECT = Z(f => l => x => g => IF(IS_EMPTY(l))(x)(_ => f(REST(l))(g(x)(FIRST(l)))(g)(_))); +const FOLD = Z(f => l => x => g => IF(IS_EMPTY(l))(x)(_ => g(f(REST(l))(x)(g))(FIRST(l))(_))); +const MAP = k => f => FOLD(k)(EMPTY)(l => x => UNSHIFT(l)(f(x))); +const RANGE = Z(f => n => m => IF(IS_LEQ(n)(m))(_ => UNSHIFT(f(INC(n))(m))(n)(_))(EMPTY)); +const SUM = l => INJECT(l)(ZERO)(ADD); +const PROD = l => INJECT(l)(ONE)(MULT); +const CONCAT = k => l => FOLD(k)(l)(UNSHIFT); +const PUSH = l => x => CONCAT(l)(UNSHIFT(EMPTY)(x)); +const REVERSE = l => FOLD(l)(EMPTY)(PUSH); +const INC_ALL = l => MAP(l)(INC); +const DOUBLE_ALL = l => MAP(l)(MULT(TWO)); +const TEN = INC(MULT(THREE)(THREE)); +const RADIX = TEN; +const FOUR = INC(THREE); +const FIVE = INC(INC(THREE)); +const FIFTEEN = MULT(THREE)(FIVE); +const FIZZ = MAP(UNSHIFT(UNSHIFT(UNSHIFT(UNSHIFT(EMPTY)(FOUR))(FOUR))(TWO))(ONE))(ADD(RADIX)); +const BUZZ = MAP(UNSHIFT(UNSHIFT(UNSHIFT(UNSHIFT(EMPTY)(FOUR))(FOUR))(THREE))(ZERO))(ADD(RADIX)); +const FIZZBUZZ = n => MAP(RANGE(ONE)(n))(m => + IF(IS_ZERO(MOD(m)(FIFTEEN)))( + CONCAT(FIZZ)(BUZZ) + )(IF(IS_ZERO(MOD(m)(THREE)))( + FIZZ + )(IF(IS_ZERO(MOD(m)(FIVE)))( + BUZZ + )( + m + ))) +); module.exports = { ZERO, ONE, TWO, THREE, TIMES, INC, ADD, MULT, POWER, DEC, SUB, TRUE, - FALSE, IF, NOT, AND, OR, IS_ZERO, IS_LEQ, IS_EQ, IS_LEQ, Y, Z, FACT + FALSE, IF, NOT, AND, OR, IS_ZERO, IS_LEQ, IS_EQ, IS_LEQ, Y, Z, FACT, + DIV, MOD, PAIR, LEFT, RIGHT, EMPTY, UNSHIFT, IS_EMPTY, FIRST, REST, INJECT, + FOLD, MAP, RANGE, SUM, PROD, CONCAT, PUSH, REVERSE, INC_ALL, DOUBLE_ALL, + TEN, RADIX, FOUR, FIVE, FIFTEEN, FIZZ, BUZZ, FIZZBUZZ };