functional-concepts
Version:
Библиотека с набором функций для возможности использования некоторых приемов функционального программирования
446 lines (333 loc) • 10.8 kB
JavaScript
import { assert, passTest } from './UnitTest.js'
import { compose, curry, flip, is, memoize, partial, pipe,
concat, each, filter, find, findIndex, last, map, reduce,
reduceRight, reverse, sort, unique, zip
} from '../src/index.js'
import * as curried from '../src/curried/index.js'
function testPipe() {
const double = x => x * 2
const increment = x => x + 1
const sample = double(increment(double(double(5)))) // 42
const result = pipe(double, double, increment, double)(5)
assert(result, sample, 'A0')
}
function testCompose() {
const double = x => x * 2
const increment = x => x + 1
const sample = double(increment(double(double(5)))) // 42
const result = compose(double, increment, double, double)(5)
assert(result, sample, 'A0')
}
function testCurry() {
const sum = (x, y, z) => x + y + z
const curriedSum = curry(sum)
const sample = sum(8, 13, 21)
assert(curriedSum(8, 13, 21), sample, 'A0')
assert(curriedSum(8, 13)(21), sample, 'A1')
assert(curriedSum(8)(13, 21), sample, 'A2')
assert(curriedSum(8)(13)(21), sample, 'A3')
}
function testIs() {
class A { }
class B extends A { }
class C extends B { }
class D { }
const a = new A()
const b = new B()
const c = new C()
const d = new D()
assert(is(B, b), true, 'A1')
assert(is(C, c), true, 'A2')
assert(is(A, a), true, 'A0')
assert(is(D, d), true, 'A3')
assert(is(A, b), true, 'B0')
assert(is(A, c), true, 'B1')
assert(is(B, c), true, 'B2')
assert(is(A, d), false, 'C0')
assert(is(B, a), false, 'D0')
assert(is(B, d), false, 'D1')
assert(is(C, a), false, 'E0')
assert(is(C, b), false, 'E1')
assert(is(C, d), false, 'E2')
assert(is(D, a), false, 'F0')
assert(is(D, b), false, 'F1')
assert(is(D, c), false, 'F2')
const isA = curried.is(A)
const isB = curried.is(B)
const isC = curried.is(C)
const isD = curried.is(D)
assert(isB(b), true, 'G1')
assert(isC(c), true, 'G2')
assert(isA(a), true, 'G0')
assert(isD(d), true, 'G3')
assert(isA(b), true, 'H0')
assert(isA(c), true, 'H1')
assert(isB(c), true, 'H2')
assert(isA(d), false, 'I0')
assert(isB(a), false, 'J0')
assert(isB(d), false, 'J1')
assert(isC(a), false, 'K0')
assert(isC(b), false, 'K1')
assert(isC(d), false, 'K2')
assert(isD(a), false, 'L0')
assert(isD(b), false, 'L1')
assert(isD(c), false, 'L2')
}
function testFlip() {
const join = (...args) => args.join(',')
const params = [ 11, 22, 33, 44, 55 ]
assert(join(...params), '11,22,33,44,55', 'A0')
assert(flip(join)(...params), '55,44,33,22,11', 'A1')
const double = x => x * 2
const increment = x => x + 1
const v0 = double(increment(double(double(5)))) // 42
const v1 = compose(double, increment, double, double)(5)
const v2 = pipe(double, double, increment, double)(5)
const prettyPipe = flip(compose)
const v3 = prettyPipe(double, double, increment, double)(5)
assert(v1, v0, 'B0')
assert(v2, v0, 'B1')
assert(v3, v0, 'B2')
}
function testPartial() {
const sum = (x, y, z) => x + y + z
const sample = sum(8, 13, 21)
assert(partial(sum, 8, 13)(21), sample, 'A1')
assert(partial(sum, 8)(13, 21), sample, 'A2')
assert(partial(sum, 8, 13, 21)(), sample, 'A3')
}
function testMemoize() {
let counter
const f = x => {
counter ++
return x + 1
}
counter = 0; f(f(f(0)))
assert(counter, 3, 'A0')
const g = memoize(f)
counter = 0; g(g(g(0)))
assert(counter, 3, 'A1')
g(g(g(0)))
assert(counter, 3, 'A2')
}
function testConcat() {
const a = []
const b = [11,22]
const c = [33,44,55]
const d = [66]
const e = []
const f = [77,88]
assert(concat().join(','), '', 'A0')
assert(concat(a).join(','), '', 'A1')
assert(concat(a, b).join(','), '11,22', 'A2')
assert(concat(b, c).join(','), '11,22,33,44,55', 'A3')
assert(concat(a, b, c).join(','), '11,22,33,44,55', 'A4')
assert(concat(a, b, c, d, e).join(','), '11,22,33,44,55,66', 'A5')
assert(concat(a, b, c, d, e, f).join(','), '11,22,33,44,55,66,77,88', 'A6')
}
function testEach() {
const a = []
const b = [11,22]
const c = [33,44,55]
const d = [66]
const e = []
const f = [77,88]
const t = a => {
let r = ''
each(x => {
r += (r.length ? ',' : '') + x
}, a)
return r
}
assert(t([]), '', 'A0')
assert(t([...a]), '', 'A1')
assert(t([...a, ...b]), '11,22', 'A2')
assert(t([...b, ...c]), '11,22,33,44,55', 'A3')
assert(t([...a, ...b, ...c]), '11,22,33,44,55', 'A4')
assert(t([...a, ...b, ...c, ...d, ...e]), '11,22,33,44,55,66', 'A5')
assert(t([...a, ...b, ...c, ...d, ...e, ...f]), '11,22,33,44,55,66,77,88', 'A6')
const w = a => {
let r = ''
curried.each(x => {
r += (r.length ? ',' : '') + x
})(a)
return r
}
assert(w([]), '', 'B0')
assert(w([...a]), '', 'B1')
assert(w([...a, ...b]), '11,22', 'B2')
assert(w([...b, ...c]), '11,22,33,44,55', 'B3')
assert(w([...a, ...b, ...c]), '11,22,33,44,55', 'B4')
assert(w([...a, ...b, ...c, ...d, ...e]), '11,22,33,44,55,66', 'B5')
assert(w([...a, ...b, ...c, ...d, ...e, ...f]), '11,22,33,44,55,66,77,88', 'B6')
}
function testFilter() {
const a = []
const b = [11,22,33,44,55,66]
const c = [11,33,55]
const p = x => x % 2 === 0
assert(filter(p, a).join(','), '', 'A0')
assert(filter(p, b).join(','), '22,44,66', 'A1')
assert(filter(p, c).join(','), '', 'A2')
const f = curried.filter(p)
assert(f(a).join(','), '', 'B0')
assert(f(b).join(','), '22,44,66', 'B1')
assert(f(c).join(','), '', 'B2')
}
function testFind() {
const a = []
const b = [11,22,33,44,55,66]
assert(find(x => x === 33, a), undefined, 'A0')
assert(find(x => x === 33, b), 33, 'A1')
assert(find(x => x === 99, b), undefined, 'A2')
assert(curried.find(x => x === 33)(a), undefined, 'B0')
assert(curried.find(x => x === 33)(b), 33, 'B1')
assert(curried.find(x => x === 99)(b), undefined, 'B2')
}
function testFindIndex() {
const a = []
const b = [11,22,33,44,55,66]
assert(findIndex(x => x === 33, a), -1, 'A0')
assert(findIndex(x => x === 33, b), 2, 'A1')
assert(findIndex(x => x === 99, b), -1, 'A2')
assert(curried.findIndex(x => x === 33)(a), -1, 'B0')
assert(curried.findIndex(x => x === 33)(b), 2, 'B1')
assert(curried.findIndex(x => x === 99)(b), -1, 'B2')
}
function testLast() {
const a = []
const b = [11,22,33,44,55,66]
const c = [11]
assert(last(a), undefined, 'A0')
assert(last(b), 66, 'A1')
assert(last(c), 11, 'A2')
}
function testMap() {
const a = []
const b = [11,22,33,44,55,66]
const c = [11]
const increase = x => x + 1
assert(map(increase, a).join(',') + '<-' + a.join(','), '<-', 'A0')
assert(map(increase, b).join(',') + '<-' + b.join(','), '12,23,34,45,56,67<-11,22,33,44,55,66', 'A1')
assert(map(increase, c).join(',') + '<-' + c.join(','), '12<-11', 'A2')
const f = curried.map(increase)
assert(f(a).join(',') + '<-' + a.join(','), '<-', 'A0')
assert(f(b).join(',') + '<-' + b.join(','), '12,23,34,45,56,67<-11,22,33,44,55,66', 'A1')
assert(f(c).join(',') + '<-' + c.join(','), '12<-11', 'A2')
}
function testReduce() {
const a = []
const b = [100,50,9]
const c = [11]
const f = (x, y) => x - y
assert(reduce(f, a), undefined, 'A0')
assert(reduce(f, b), 41, 'A1')
assert(reduce(f, c), 11, 'A2')
const g = curried.reduce(f)
assert(g(a), undefined, 'B0')
assert(g(b), 41, 'B1')
assert(g(c), 11, 'B2')
}
function testReduceRight() {
const a = []
const b = [100,50,9]
const c = [11]
const f = (x, y) => x - y
assert(reduceRight(f, a), undefined, 'A0')
assert(reduceRight(f, b), -141, 'A1')
assert(reduceRight(f, c), 11, 'A2')
const g = curried.reduceRight(f)
assert(g(a), undefined, 'B0')
assert(g(b), -141, 'B1')
assert(g(c), 11, 'B2')
}
function testReverse() {
const a = []
const b = [11,22,33,44,55,66]
const c = [11]
assert(reverse(a).join(',') + '<-' + a.join(','), '<-', 'A0')
assert(reverse(b).join(',') + '<-' + b.join(','), '66,55,44,33,22,11<-11,22,33,44,55,66', 'A1')
assert(reverse(c).join(',') + '<-' + c.join(','), '11<-11', 'A2')
}
function testSort() {
const a = []
const b = [11,33,22,44,55,77,66]
const c = [22,11]
const d = [33,22,11]
const e = [11,22,33]
const compare = (x, y) => x - y
assert(sort(compare, a).join(',') + '<-' + a.join(','), '<-', 'A0')
assert(sort(compare, b).join(',') + '<-' + b.join(','), '11,22,33,44,55,66,77<-11,33,22,44,55,77,66', 'A1')
assert(sort(compare, c).join(',') + '<-' + c.join(','), '11,22<-22,11', 'A2')
assert(sort(compare, d).join(',') + '<-' + d.join(','), '11,22,33<-33,22,11', 'A3')
assert(sort(compare, e).join(',') + '<-' + e.join(','), '11,22,33<-11,22,33', 'A4')
const f = curried.sort(compare)
assert(f(a).join(',') + '<-' + a.join(','), '<-', 'B0')
assert(f(b).join(',') + '<-' + b.join(','), '11,22,33,44,55,66,77<-11,33,22,44,55,77,66', 'B1')
assert(f(c).join(',') + '<-' + c.join(','), '11,22<-22,11', 'B2')
assert(f(d).join(',') + '<-' + d.join(','), '11,22,33<-33,22,11', 'B3')
assert(f(e).join(',') + '<-' + e.join(','), '11,22,33<-11,22,33', 'B4')
}
function testUnique() {
const a = []
const b = [11,33,33,11,22]
const c = [22,11]
const d = [33]
assert(unique(a).join(',') + '<-' + a.join(','), '<-', 'A0')
assert(unique(b).join(',') + '<-' + b.join(','), '11,33,22<-11,33,33,11,22', 'A1')
assert(unique(c).join(',') + '<-' + c.join(','), '22,11<-22,11', 'A2')
assert(unique(d).join(',') + '<-' + d.join(','), '33<-33', 'A3')
}
function testZip() {
const a = [
[11,22,33]
]
const b = [
[11,22,33],
[44,55,66]
]
const c = [
[11,22,33,44],
[55,66,77,88],
[99,10,20,30]
]
const d = []
const line1 = points => map(([x]) => `(${x})`, points).join(',')
const line2 = points => map(([x, y]) => `(${x};${y})`, points).join(',')
const line3 = points => map(([x, y, z]) => `(${x};${y};${z})`, points).join(',')
const p = (...xs) => xs
assert(line1(zip(p, ...a)), '(11),(22),(33)', 'A0')
assert(line2(zip(p, ...b)), '(11;44),(22;55),(33;66)', 'A1')
assert(line3(zip(p, ...c)), '(11;55;99),(22;66;10),(33;77;20),(44;88;30)', 'A2')
assert(line1(zip(p, ...d)), '', 'A3')
assert(line2(zip(p, ...d)), '', 'A4')
assert(line3(zip(p, ...d)), '', 'A5')
const f = curried.zip(p)
assert(line1(f(...a)), '(11),(22),(33)', 'B0')
assert(line2(f(...b)), '(11;44),(22;55),(33;66)', 'B1')
assert(line3(f(...c)), '(11;55;99),(22;66;10),(33;77;20),(44;88;30)', 'B2')
assert(line1(f(...d)), '', 'B3')
assert(line2(f(...d)), '', 'B4')
assert(line3(f(...d)), '', 'B5')
}
passTest(testPipe)
passTest(testCompose)
passTest(testCurry)
passTest(testIs)
passTest(testFlip)
passTest(testPartial)
passTest(testMemoize)
passTest(testConcat)
passTest(testEach)
passTest(testFilter)
passTest(testFind)
passTest(testFindIndex)
passTest(testLast)
passTest(testMap)
passTest(testReduce)
passTest(testReduceRight)
passTest(testReverse)
passTest(testSort)
passTest(testUnique)
passTest(testZip)
console.log('\nAll tests passed.\n')