Skip to content

Commit

Permalink
feat(numerals): Add encodeNumeral and decodeNumeral
Browse files Browse the repository at this point in the history
  • Loading branch information
benji6 committed Feb 16, 2018
1 parent fa098a7 commit 1c231e3
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 101 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Expand Up @@ -2,6 +2,7 @@
"extends": "benji6",
"rules": {
"no-unused-vars": 0,
"no-use-before-define": 0
"no-use-before-define": 0,
"prefer-spread": 0
}
}
36 changes: 29 additions & 7 deletions dist/index.js
Expand Up @@ -109,11 +109,11 @@ var encodeBoolean = function encodeBoolean(a) {

// This is how numerals are encoded. They take a function and a value then apply that function to the value or the previous result of application n times where n is the number being encoded. In JavaScript we can decode numerals simply like this:
// ```javascript
// const decodeNumber = a => a(b => b + 1)(0)
// decodeNumber(zero) // => 0
// decodeNumber(one) // => 1
// decodeNumber(two) // => 2
// decodeNumber(three) // => 3
// const decodeNumeral = a => a(b => b + 1)(0)
// decodeNumeral(zero) // => 0
// decodeNumeral(one) // => 1
// decodeNumeral(two) // => 2
// decodeNumeral(three) // => 3
// ```

// zero is the KI combinator just like False - not very type safe!
Expand Down Expand Up @@ -260,6 +260,28 @@ var exp = function exp(a) {
};
};

// `decodeNumeral` takes a Church encoded numeral and returns the corresponding JS number
// ```javascript
// decodeNumeral(three) // => 3
// ```
var decodeNumeral = function decodeNumeral(a) {
return a(function (b) {
return b + 1;
})(0);
};

// `encodeNumeral` takes a JS number and returns the corresponding Church encoded numeral
// ```javascript
// encodeNumeral(3) // => three
// ```
var encodeNumeral = function encodeNumeral(n) {
return function (f) {
return function (x) {
return Array.apply(null, { length: n }).reduce(f, x);
};
};
};

// `isZero` takes a value and returns Church encoded `True` if it is a Church encoded `zero` and `False` otherwise
// ```javascript
// isZero(zero) // => True
Expand Down Expand Up @@ -702,8 +724,6 @@ var reject = function reject(f) {
})(nil);
};

// Welcome to the docs!

exports.True = True;
exports.False = False;
exports.If = If;
Expand All @@ -730,6 +750,8 @@ exports.add = add;
exports.sub = sub;
exports.mult = mult;
exports.exp = exp;
exports.decodeNumeral = decodeNumeral;
exports.encodeNumeral = encodeNumeral;
exports.isZero = isZero;
exports.lte = lte;
exports.gte = gte;
Expand Down
22 changes: 17 additions & 5 deletions src/numerals.js
@@ -1,10 +1,10 @@
// This is how numerals are encoded. They take a function and a value then apply that function to the value or the previous result of application n times where n is the number being encoded. In JavaScript we can decode numerals simply like this:
// ```javascript
// const decodeNumber = a => a(b => b + 1)(0)
// decodeNumber(zero) // => 0
// decodeNumber(one) // => 1
// decodeNumber(two) // => 2
// decodeNumber(three) // => 3
// const decodeNumeral = a => a(b => b + 1)(0)
// decodeNumeral(zero) // => 0
// decodeNumeral(one) // => 1
// decodeNumeral(two) // => 2
// decodeNumeral(three) // => 3
// ```

// zero is the KI combinator just like False - not very type safe!
Expand Down Expand Up @@ -64,3 +64,15 @@ export const mult = a => b => c => a(b(c))
// exp(three)(two) // => nine
// ```
export const exp = a => b => b(a)

// `decodeNumeral` takes a Church encoded numeral and returns the corresponding JS number
// ```javascript
// decodeNumeral(three) // => 3
// ```
export const decodeNumeral = a => a(b => b + 1)(0)

// `encodeNumeral` takes a JS number and returns the corresponding Church encoded numeral
// ```javascript
// encodeNumeral(3) // => three
// ```
export const encodeNumeral = n => f => x => Array.apply(null, {length: n}).reduce(f, x)
1 change: 0 additions & 1 deletion test/_tools.js
Expand Up @@ -3,4 +3,3 @@ import {foldl} from '../src'
const append = xs => x => xs.concat([x])

export const decodeList = foldl(append)([])
export const decodeNumber = a => a(b => b + 1)(0)
91 changes: 46 additions & 45 deletions test/lists.js
@@ -1,12 +1,13 @@
import test from 'tape'
import {decodeList, decodeNumber} from './_tools'
import {decodeList} from './_tools'
import {
add,
all,
append,
concat,
cons,
decodeBoolean,
decodeNumeral,
drop,
filter,
foldl,
Expand Down Expand Up @@ -66,52 +67,52 @@ test('Lists - all', t => {
})

test('Lists - append', t => {
t.deepEqual(decodeList(append(four)(l123)).map(decodeNumber), [1, 2, 3, 4])
t.deepEqual(decodeList(append(four)(l123)).map(decodeNumeral), [1, 2, 3, 4])
t.end()
})

test('Lists - concat', t => {
t.deepEqual(decodeList(concat(l123)(l246)).map(decodeNumber), [1, 2, 3, 2, 4, 6])
t.deepEqual(decodeList(concat(l123)(l246)).map(decodeNumeral), [1, 2, 3, 2, 4, 6])
t.end()
})

test('Lists - cons', t => {
const testList = cons(one)(cons(two)(cons(three)(nil)))
t.equal(decodeNumber(head(testList)), 1)
t.equal(decodeNumber(head(tail(testList))), 2)
t.equal(decodeNumber(head(tail(tail(testList)))), 3)
t.equal(decodeNumeral(head(testList)), 1)
t.equal(decodeNumeral(head(tail(testList))), 2)
t.equal(decodeNumeral(head(tail(tail(testList)))), 3)
t.end()
})

test('Lists - drop', t => {
t.deepEqual(decodeList(drop(one)(l123)).map(decodeNumber), [2, 3])
t.deepEqual(decodeList(drop(two)(l123)).map(decodeNumber), [3])
t.deepEqual(decodeList(drop(one)(l123)).map(decodeNumeral), [2, 3])
t.deepEqual(decodeList(drop(two)(l123)).map(decodeNumeral), [3])
t.end()
})

test('Lists - filter', t => {
t.deepEqual(decodeList(filter(lt(three))(l123)).map(decodeNumber), [])
t.deepEqual(decodeList(filter(lt(two))(l123)).map(decodeNumber), [3])
t.deepEqual(decodeList(filter(lt(one))(l123)).map(decodeNumber), [2, 3])
t.deepEqual(decodeList(filter(lt(three))(l123)).map(decodeNumeral), [])
t.deepEqual(decodeList(filter(lt(two))(l123)).map(decodeNumeral), [3])
t.deepEqual(decodeList(filter(lt(one))(l123)).map(decodeNumeral), [2, 3])
t.end()
})

test('Lists - foldl', t => {
t.equal(decodeNumber(foldl(add)(three)(l123)), 9)
t.deepEqual(foldl(push)([])(l123).map(decodeNumber), [1, 2, 3])
t.equal(decodeNumeral(foldl(add)(three)(l123)), 9)
t.deepEqual(foldl(push)([])(l123).map(decodeNumeral), [1, 2, 3])
t.end()
})

test('Lists - foldr', t => {
t.equal(decodeNumber(foldr(add)(three)(l123)), 9)
t.deepEqual(foldr(pushFlipped)([])(l123).map(decodeNumber), [3, 2, 1])
t.equal(decodeNumeral(foldr(add)(three)(l123)), 9)
t.deepEqual(foldr(pushFlipped)([])(l123).map(decodeNumeral), [3, 2, 1])
t.end()
})

test('Lists - head', t => {
t.equal(decodeNumber(head(l123)), 1)
t.equal(decodeNumber(head(tail(l123))), 2)
t.equal(decodeNumber(head(tail(tail(l123)))), 3)
t.equal(decodeNumeral(head(l123)), 1)
t.equal(decodeNumeral(head(tail(l123))), 2)
t.equal(decodeNumeral(head(tail(tail(l123)))), 3)
t.end()
})

Expand All @@ -122,18 +123,18 @@ test('Lists - isNil', t => {
})

test('Lists - last', t => {
t.equals(decodeNumber(last(l123)), 3)
t.equals(decodeNumeral(last(l123)), 3)
t.end()
})

test('Lists - length', t => {
t.equals(decodeNumber(length(l123)), 3)
t.equals(decodeNumber(length(tail(l123))), 2)
t.equals(decodeNumeral(length(l123)), 3)
t.equals(decodeNumeral(length(tail(l123))), 2)
t.end()
})

test('Lists - map', t => {
t.deepEqual(decodeList(map(mult(two))(l123)).map(decodeNumber), [2, 4, 6])
t.deepEqual(decodeList(map(mult(two))(l123)).map(decodeNumeral), [2, 4, 6])
t.end()
})

Expand All @@ -148,28 +149,28 @@ test('Lists - none', t => {
})

test('Lists - nth', t => {
t.equal(decodeNumber(nth(zero)(l123)), 1)
t.equal(decodeNumber(nth(one)(l123)), 2)
t.equal(decodeNumber(nth(two)(l246)), 6)
t.equal(decodeNumeral(nth(zero)(l123)), 1)
t.equal(decodeNumeral(nth(one)(l123)), 2)
t.equal(decodeNumeral(nth(two)(l246)), 6)
t.end()
})

test('Lists - prepend', t => {
t.deepEqual(decodeList(prepend(zero)(l123)).map(decodeNumber), [0, 1, 2, 3])
t.deepEqual(decodeList(prepend(zero)(l123)).map(decodeNumeral), [0, 1, 2, 3])
t.end()
})

test('Lists - range', t => {
t.deepEqual(decodeList(range(zero)(three)).map(decodeNumber), [0, 1, 2, 3])
t.deepEqual(decodeList(range(one)(three)).map(decodeNumber), [1, 2, 3])
t.deepEqual(decodeList(range(two)(three)).map(decodeNumber), [2, 3])
t.deepEqual(decodeList(range(zero)(three)).map(decodeNumeral), [0, 1, 2, 3])
t.deepEqual(decodeList(range(one)(three)).map(decodeNumeral), [1, 2, 3])
t.deepEqual(decodeList(range(two)(three)).map(decodeNumeral), [2, 3])
t.end()
})

test('Lists - reject', t => {
t.deepEqual(decodeList(reject(gte(three))(l123)).map(decodeNumber), [])
t.deepEqual(decodeList(reject(gte(two))(l123)).map(decodeNumber), [3])
t.deepEqual(decodeList(reject(gte(one))(l123)).map(decodeNumber), [2, 3])
t.deepEqual(decodeList(reject(gte(three))(l123)).map(decodeNumeral), [])
t.deepEqual(decodeList(reject(gte(two))(l123)).map(decodeNumeral), [3])
t.deepEqual(decodeList(reject(gte(one))(l123)).map(decodeNumeral), [2, 3])
t.end()
})

Expand All @@ -179,46 +180,46 @@ test('Lists - repeat', t => {
})

test('Lists - reverse', t => {
t.deepEqual(decodeList(reverse(l123)).map(decodeNumber), [3, 2, 1])
t.deepEqual(decodeList(reverse(l123)).map(decodeNumeral), [3, 2, 1])
t.end()
})

test('Lists - slice', t => {
t.deepEqual(decodeList(slice(one)(two)(l123)).map(decodeNumber), [2])
t.deepEqual(decodeList(slice(one)(three)(l123)).map(decodeNumber), [2, 3])
t.deepEqual(decodeList(slice(one)(two)(l123)).map(decodeNumeral), [2])
t.deepEqual(decodeList(slice(one)(three)(l123)).map(decodeNumeral), [2, 3])
t.end()
})

test('Lists - sum', t => {
t.deepEqual(decodeNumber(sum(l123)), 6)
t.deepEqual(decodeNumber(sum(l246)), 12)
t.deepEqual(decodeNumeral(sum(l123)), 6)
t.deepEqual(decodeNumeral(sum(l246)), 12)
t.end()
})

test('Lists - take', t => {
t.deepEqual(decodeList(take(one)(l123)).map(decodeNumber), [1])
t.deepEqual(decodeList(take(two)(l123)).map(decodeNumber), [1, 2])
t.deepEqual(decodeList(take(three)(l123)).map(decodeNumber), [1, 2, 3])
t.deepEqual(decodeList(take(one)(l123)).map(decodeNumeral), [1])
t.deepEqual(decodeList(take(two)(l123)).map(decodeNumeral), [1, 2])
t.deepEqual(decodeList(take(three)(l123)).map(decodeNumeral), [1, 2, 3])
t.end()
})

test('Lists - tail', t => {
t.equal(decodeNumber(head(tail(l123))), 2)
t.equal(decodeNumber(head(tail(tail(l123)))), 3)
t.equal(decodeNumeral(head(tail(l123))), 2)
t.equal(decodeNumeral(head(tail(tail(l123)))), 3)
t.end()
})

test('Lists - zip', t => {
t.deepEqual(
decodeList(zip(l123)(l246)).map(decodeList).map(xs => xs.map(decodeNumber)),
decodeList(zip(l123)(l246)).map(decodeList).map(xs => xs.map(decodeNumeral)),
[
[1, 2],
[2, 4],
[3, 6],
]
)
t.deepEqual(
decodeList(zip(l1234)(l246)).map(decodeList).map(xs => xs.map(decodeNumber)),
decodeList(zip(l1234)(l246)).map(decodeList).map(xs => xs.map(decodeNumeral)),
[
[1, 2],
[2, 4],
Expand All @@ -230,7 +231,7 @@ test('Lists - zip', t => {

test('Lists - zipWith', t => {
t.deepEqual(
decodeList(zipWith(add)(l123)(l246)).map(decodeNumber),
decodeList(zipWith(add)(l123)(l246)).map(decodeNumeral),
[3, 6, 9]
)
t.end()
Expand Down

0 comments on commit 1c231e3

Please sign in to comment.