From badab02c9fb833265804200e5ecafe521d0b0153 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 31 May 2019 16:10:22 +0200 Subject: [PATCH] make Set functions data-last --- docs/modules/Set.ts.md | 36 +++++----- src/Set.ts | 151 +++++++++++++++++++++-------------------- test/Set.ts | 69 +++++++++---------- 3 files changed, 131 insertions(+), 125 deletions(-) diff --git a/docs/modules/Set.ts.md b/docs/modules/Set.ts.md index 1095a14cb..39268920f 100644 --- a/docs/modules/Set.ts.md +++ b/docs/modules/Set.ts.md @@ -53,7 +53,7 @@ Added in v2.0.0 **Signature** ```ts -export function chain(E: Eq): (set: Set, f: (x: A) => Set) => Set { ... } +export function chain(E: Eq): (f: (x: A) => Set) => (set: Set) => Set { ... } ``` Added in v2.0.0 @@ -96,7 +96,7 @@ Test if a value is a member of a set **Signature** ```ts -export function elem(E: Eq): (a: A, x: Set) => boolean { ... } +export function elem(E: Eq): (a: A) => (set: Set) => boolean { ... } ``` Added in v2.0.0 @@ -106,7 +106,7 @@ Added in v2.0.0 **Signature** ```ts -export function every(x: Set, predicate: Predicate): boolean { ... } +export function every(predicate: Predicate): (set: Set) => boolean { ... } ``` Added in v2.0.0 @@ -116,8 +116,8 @@ Added in v2.0.0 **Signature** ```ts -export function filter(x: Set, predicate: Refinement): Set -export function filter(x: Set, predicate: Predicate): Set { ... } +export function filter(refinement: Refinement): (set: Set) => Set +export function filter(predicate: Predicate): (set: Set) => Set { ... } ``` Added in v2.0.0 @@ -127,7 +127,7 @@ Added in v2.0.0 **Signature** ```ts -export function filterMap(E: Eq): (fa: Set, f: (a: A) => Option) => Set { ... } +export function filterMap(E: Eq): (f: (a: A) => Option) => (fa: Set) => Set { ... } ``` Added in v2.0.0 @@ -137,7 +137,7 @@ Added in v2.0.0 **Signature** ```ts -export function foldMap(O: Ord, M: Monoid): (fa: Set, f: (a: A) => M) => M { ... } +export function foldMap(O: Ord, M: Monoid): (f: (a: A) => M) => (fa: Set) => M { ... } ``` Added in v2.0.0 @@ -201,7 +201,7 @@ Insert a value into a set **Signature** ```ts -export function insert(E: Eq): (a: A, x: Set) => Set { ... } +export function insert(E: Eq): (a: A) => (set: Set) => Set { ... } ``` Added in v2.0.0 @@ -213,7 +213,7 @@ The set of elements which are in both the first and second set **Signature** ```ts -export function intersection(E: Eq): (x: Set, y: Set) => Set { ... } +export function intersection(E: Eq): (set: Set, y: Set) => Set { ... } ``` Added in v2.0.0 @@ -225,7 +225,7 @@ Projects a Set through a function **Signature** ```ts -export function map(E: Eq): (set: Set, f: (x: A) => B) => Set { ... } +export function map(E: Eq): (f: (x: A) => B) => (set: Set) => Set { ... } ``` Added in v2.0.0 @@ -235,8 +235,8 @@ Added in v2.0.0 **Signature** ```ts -export function partition(x: Set, predicate: Refinement): Separated, Set> -export function partition(x: Set, predicate: Predicate): Separated, Set> { ... } +export function partition(refinement: Refinement): (set: Set) => Separated, Set> +export function partition(predicate: Predicate): (set: Set) => Separated, Set> { ... } ``` Added in v2.0.0 @@ -249,7 +249,7 @@ Added in v2.0.0 export function partitionMap( SL: Eq, SR: Eq -): (x: Set, f: (a: A) => Either) => Separated, Set> { ... } +): (f: (a: A) => Either) => (set: Set) => Separated, Set> { ... } ``` Added in v2.0.0 @@ -259,7 +259,7 @@ Added in v2.0.0 **Signature** ```ts -export function reduce(O: Ord): (fa: Set, b: B, f: (b: B, a: A) => B) => B { ... } +export function reduce(O: Ord): (b: B, f: (b: B, a: A) => B) => (fa: Set) => B { ... } ``` Added in v2.0.0 @@ -271,7 +271,7 @@ Delete a value from a set **Signature** ```ts -export function remove(E: Eq): (a: A, x: Set) => Set { ... } +export function remove(E: Eq): (a: A) => (set: Set) => Set { ... } ``` Added in v2.0.0 @@ -303,7 +303,7 @@ Added in v2.0.0 **Signature** ```ts -export function some(x: Set, predicate: Predicate): boolean { ... } +export function some(predicate: Predicate): (set: Set) => boolean { ... } ``` Added in v2.0.0 @@ -325,7 +325,7 @@ Added in v2.0.0 **Signature** ```ts -export function toArray(O: Ord): (x: Set) => Array { ... } +export function toArray(O: Ord): (set: Set) => Array { ... } ``` Added in v2.0.0 @@ -337,7 +337,7 @@ Form the union of two sets **Signature** ```ts -export function union(E: Eq): (x: Set, y: Set) => Set { ... } +export function union(E: Eq): (set: Set, y: Set) => Set { ... } ``` Added in v2.0.0 diff --git a/src/Set.ts b/src/Set.ts index 12a8106d2..366ce71b5 100644 --- a/src/Set.ts +++ b/src/Set.ts @@ -34,7 +34,7 @@ export const empty: Set = new Set() /** * @since 2.0.0 */ -export function toArray(O: Ord): (x: Set) => Array { +export function toArray(O: Ord): (set: Set) => Array { return x => { const r: Array = [] x.forEach(e => r.push(e)) @@ -53,14 +53,16 @@ export function getEq(E: Eq): Eq> { /** * @since 2.0.0 */ -export function some(x: Set, predicate: Predicate): boolean { - const values = x.values() - let e: IteratorResult - let found = false - while (!found && !(e = values.next()).done) { - found = predicate(e.value) +export function some(predicate: Predicate): (set: Set) => boolean { + return set => { + const values = set.values() + let e: IteratorResult + let found = false + while (!found && !(e = values.next()).done) { + found = predicate(e.value) + } + return found } - return found } /** @@ -68,13 +70,13 @@ export function some(x: Set, predicate: Predicate): boolean { * * @since 2.0.0 */ -export function map(E: Eq): (set: Set, f: (x: A) => B) => Set { +export function map(E: Eq): (f: (x: A) => B) => (set: Set) => Set { const elemE = elem(E) - return (set, f) => { + return f => set => { const r = new Set() set.forEach(e => { const v = f(e) - if (!elemE(v, r)) { + if (!elemE(v)(r)) { r.add(v) } }) @@ -85,20 +87,20 @@ export function map(E: Eq): (set: Set, f: (x: A) => B) => Set { /** * @since 2.0.0 */ -export function every(x: Set, predicate: Predicate): boolean { - return !some(x, not(predicate)) +export function every(predicate: Predicate): (set: Set) => boolean { + return not(some(not(predicate))) } /** * @since 2.0.0 */ -export function chain(E: Eq): (set: Set, f: (x: A) => Set) => Set { +export function chain(E: Eq): (f: (x: A) => Set) => (set: Set) => Set { const elemE = elem(E) - return (set, f) => { + return f => set => { let r = new Set() set.forEach(e => { f(e).forEach(e => { - if (!elemE(e, r)) { + if (!elemE(e)(r)) { r.add(e) } }) @@ -114,46 +116,50 @@ export function chain(E: Eq): (set: Set, f: (x: A) => Set) => Set */ export function subset(E: Eq): (x: Set, y: Set) => boolean { const elemE = elem(E) - return (x, y) => every(x, a => elemE(a, y)) + return (x, y) => every((a: A) => elemE(a)(y))(x) } /** * @since 2.0.0 */ -export function filter(x: Set, predicate: Refinement): Set -export function filter(x: Set, predicate: Predicate): Set -export function filter(x: Set, predicate: Predicate): Set { - const values = x.values() - let e: IteratorResult - let r = new Set() - while (!(e = values.next()).done) { - const value = e.value - if (predicate(value)) { - r.add(value) +export function filter(refinement: Refinement): (set: Set) => Set +export function filter(predicate: Predicate): (set: Set) => Set +export function filter(predicate: Predicate): (set: Set) => Set { + return set => { + const values = set.values() + let e: IteratorResult + let r = new Set() + while (!(e = values.next()).done) { + const value = e.value + if (predicate(value)) { + r.add(value) + } } + return r } - return r } /** * @since 2.0.0 */ -export function partition(x: Set, predicate: Refinement): Separated, Set> -export function partition(x: Set, predicate: Predicate): Separated, Set> -export function partition(x: Set, predicate: Predicate): Separated, Set> { - const values = x.values() - let e: IteratorResult - let right = new Set() - let left = new Set() - while (!(e = values.next()).done) { - const value = e.value - if (predicate(value)) { - right.add(value) - } else { - left.add(value) +export function partition(refinement: Refinement): (set: Set) => Separated, Set> +export function partition(predicate: Predicate): (set: Set) => Separated, Set> +export function partition(predicate: Predicate): (set: Set) => Separated, Set> { + return set => { + const values = set.values() + let e: IteratorResult + let right = new Set() + let left = new Set() + while (!(e = values.next()).done) { + const value = e.value + if (predicate(value)) { + right.add(value) + } else { + left.add(value) + } } + return { left, right } } - return { left, right } } /** @@ -161,8 +167,8 @@ export function partition(x: Set, predicate: Predicate): Separated(E: Eq): (a: A, x: Set) => boolean { - return (a, x) => some(x, (ax: A) => E.equals(a, ax)) +export function elem(E: Eq): (a: A) => (set: Set) => boolean { + return a => some((ax: A) => E.equals(a, ax)) } /** @@ -170,7 +176,7 @@ export function elem(E: Eq): (a: A, x: Set) => boolean { * * @since 2.0.0 */ -export function union(E: Eq): (x: Set, y: Set) => Set { +export function union(E: Eq): (set: Set, y: Set) => Set { const elemE = elem(E) return (x, y) => { if (x === empty) { @@ -181,7 +187,7 @@ export function union(E: Eq): (x: Set, y: Set) => Set { } const r = new Set(x) y.forEach(e => { - if (!elemE(e, r)) { + if (!elemE(e)(r)) { r.add(e) } }) @@ -194,7 +200,7 @@ export function union(E: Eq): (x: Set, y: Set) => Set { * * @since 2.0.0 */ -export function intersection(E: Eq): (x: Set, y: Set) => Set { +export function intersection(E: Eq): (set: Set, y: Set) => Set { const elemE = elem(E) return (x, y) => { if (x === empty || y === empty) { @@ -202,7 +208,7 @@ export function intersection(E: Eq): (x: Set, y: Set) => Set { } const r = new Set() x.forEach(e => { - if (elemE(e, y)) { + if (elemE(e)(y)) { r.add(e) } }) @@ -216,9 +222,9 @@ export function intersection(E: Eq): (x: Set, y: Set) => Set { export function partitionMap( SL: Eq, SR: Eq -): (x: Set, f: (a: A) => Either) => Separated, Set> { - return (x: Set, f: (a: A) => Either) => { - const values = x.values() +): (f: (a: A) => Either) => (set: Set) => Separated, Set> { + return (f: (a: A) => Either) => (set: Set) => { + const values = set.values() let e: IteratorResult let left = new Set() let right = new Set() @@ -228,12 +234,12 @@ export function partitionMap( const v = f(e.value) switch (v._tag) { case 'Left': - if (!hasL(v.left, left)) { + if (!hasL(v.left)(left)) { left.add(v.left) } break case 'Right': - if (!hasR(v.right, right)) { + if (!hasR(v.right)(right)) { right.add(v.right) } break @@ -257,7 +263,7 @@ export function partitionMap( */ export function difference(E: Eq): (x: Set, y: Set) => Set { const elemE = elem(E) - return (x, y) => filter(x, a => !elemE(a, y)) + return (x, y) => filter((a: A) => !elemE(a)(y))(x) } /** @@ -282,17 +288,17 @@ export function getIntersectionSemigroup(E: Eq): Semigroup> { /** * @since 2.0.0 */ -export function reduce(O: Ord): (fa: Set, b: B, f: (b: B, a: A) => B) => B { +export function reduce(O: Ord): (b: B, f: (b: B, a: A) => B) => (fa: Set) => B { const toArrayO = toArray(O) - return (fa, b, f) => toArrayO(fa).reduce(f, b) + return (b, f) => fa => toArrayO(fa).reduce(f, b) } /** * @since 2.0.0 */ -export function foldMap(O: Ord, M: Monoid): (fa: Set, f: (a: A) => M) => M { +export function foldMap(O: Ord, M: Monoid): (f: (a: A) => M) => (fa: Set) => M { const toArrayO = toArray(O) - return (fa, f) => toArrayO(fa).reduce((b, a) => M.concat(b, f(a)), M.empty) + return f => fa => toArrayO(fa).reduce((b, a) => M.concat(b, f(a)), M.empty) } /** @@ -309,15 +315,15 @@ export function singleton(a: A): Set { * * @since 2.0.0 */ -export function insert(E: Eq): (a: A, x: Set) => Set { +export function insert(E: Eq): (a: A) => (set: Set) => Set { const elemE = elem(E) - return (a, x) => { - if (!elemE(a, x)) { - const r = new Set(x) + return a => set => { + if (!elemE(a)(set)) { + const r = new Set(set) r.add(a) return r } else { - return x + return set } } } @@ -327,8 +333,8 @@ export function insert(E: Eq): (a: A, x: Set) => Set { * * @since 2.0.0 */ -export function remove(E: Eq): (a: A, x: Set) => Set { - return (a, x) => filter(x, (ax: A) => !E.equals(a, ax)) +export function remove(E: Eq): (a: A) => (set: Set) => Set { + return a => set => filter((ax: A) => !E.equals(a, ax))(set) } /** @@ -343,7 +349,7 @@ export function fromArray(E: Eq): (as: Array) => Set { const has = elem(E) for (let i = 0; i < len; i++) { const a = as[i] - if (!has(a, r)) { + if (!has(a)(r)) { r.add(a) } } @@ -355,8 +361,7 @@ export function fromArray(E: Eq): (as: Array) => Set { * @since 2.0.0 */ export function compact(E: Eq): (fa: Set>) => Set { - const filterMapE = filterMap(E) - return fa => filterMapE(fa, identity) + return filterMap(E)(identity) } /** @@ -371,12 +376,12 @@ export function separate(EL: Eq, ER: Eq): (fa: Set>) => fa.forEach(e => { switch (e._tag) { case 'Left': - if (!elemEL(e.left, left)) { + if (!elemEL(e.left)(left)) { left.add(e.left) } break case 'Right': - if (!elemER(e.right, right)) { + if (!elemER(e.right)(right)) { right.add(e.right) } break @@ -389,13 +394,13 @@ export function separate(EL: Eq, ER: Eq): (fa: Set>) => /** * @since 2.0.0 */ -export function filterMap(E: Eq): (fa: Set, f: (a: A) => Option) => Set { +export function filterMap(E: Eq): (f: (a: A) => Option) => (fa: Set) => Set { const elemE = elem(E) - return (fa, f) => { + return f => fa => { const r: Set = new Set() fa.forEach(a => { const ob = f(a) - if (ob._tag === 'Some' && !elemE(ob.value, r)) { + if (ob._tag === 'Some' && !elemE(ob.value)(r)) { r.add(ob.value) } }) diff --git a/test/Set.ts b/test/Set.ts index c4d062eee..b6333866e 100644 --- a/test/Set.ts +++ b/test/Set.ts @@ -59,27 +59,27 @@ describe('Set', () => { }) it('some', () => { - assert.strictEqual(some(new Set(), (s: string) => s.trim() === ''), false) - assert.strictEqual(some(new Set([1, 2, 3]), gte2), true) - assert.strictEqual(some(new Set([1]), gte2), false) + assert.strictEqual(some((s: string) => s.trim() === '')(new Set()), false) + assert.strictEqual(some(gte2)(new Set([1, 2, 3])), true) + assert.strictEqual(some(gte2)(new Set([1])), false) }) it('map', () => { - assert.deepStrictEqual(map(eqNumber)(new Set([]), x => x % 2), new Set([])) - assert.deepStrictEqual(map(eqNumber)(new Set([1, 2, 3, 4]), x => x % 2), new Set([0, 1])) - assert.deepStrictEqual(map(eqString)(new Set([1, 2, 3, 4]), x => `${x % 2}`), new Set(['0', '1'])) + assert.deepStrictEqual(map(eqNumber)((n: number) => n % 2)(new Set([])), new Set([])) + assert.deepStrictEqual(map(eqNumber)((n: number) => n % 2)(new Set([1, 2, 3, 4])), new Set([0, 1])) + assert.deepStrictEqual(map(eqString)((n: number) => `${n % 2}`)(new Set([1, 2, 3, 4])), new Set(['0', '1'])) }) it('every', () => { - assert.strictEqual(every(new Set([1, 2, 3]), gte2), false) - assert.strictEqual(every(new Set([2, 3]), gte2), true) + assert.strictEqual(every(gte2)(new Set([1, 2, 3])), false) + assert.strictEqual(every(gte2)(new Set([2, 3])), true) }) it('chain', () => { - assert.deepStrictEqual(chain(eqString)(new Set([]), x => new Set([x.toString()])), new Set([])) - assert.deepStrictEqual(chain(eqString)(new Set([1, 2]), () => new Set([])), new Set([])) + assert.deepStrictEqual(chain(eqString)((n: number) => new Set([n.toString()]))(new Set([])), new Set([])) + assert.deepStrictEqual(chain(eqString)(() => new Set([]))(new Set([1, 2])), new Set([])) assert.deepStrictEqual( - chain(eqString)(new Set([1, 2]), x => new Set([`${x}`, `${x + 1}`])), + chain(eqString)((n: number) => new Set([`${n}`, `${n + 1}`]))(new Set([1, 2])), new Set(['1', '2', '3']) ) }) @@ -90,28 +90,26 @@ describe('Set', () => { }) it('filter', () => { - assert.deepStrictEqual(filter(new Set([1, 2, 3]), gte2), new Set([2, 3])) + assert.deepStrictEqual(filter(gte2)(new Set([1, 2, 3])), new Set([2, 3])) // refinements - const x: Set = new Set([1, 'a', 2]) const isNumber = (u: string | number): u is number => typeof u === 'number' - const actual = filter(x, isNumber) + const actual = filter(isNumber)(new Set([1, 'a', 2])) assert.deepStrictEqual(actual, new Set([1, 2])) }) it('partition', () => { - assert.deepStrictEqual(partition(new Set([]), () => true), { right: new Set([]), left: new Set([]) }) - assert.deepStrictEqual(partition(new Set([1]), () => true), { right: new Set([1]), left: new Set([]) }) - assert.deepStrictEqual(partition(new Set([1]), () => false), { right: new Set([]), left: new Set([1]) }) - assert.deepStrictEqual(partition(new Set([1, 2, 3, 4]), x => x % 2 === 0), { + assert.deepStrictEqual(partition(() => true)(new Set([])), { right: new Set([]), left: new Set([]) }) + assert.deepStrictEqual(partition(() => true)(new Set([1])), { right: new Set([1]), left: new Set([]) }) + assert.deepStrictEqual(partition(() => false)(new Set([1])), { right: new Set([]), left: new Set([1]) }) + assert.deepStrictEqual(partition((n: number) => n % 2 === 0)(new Set([1, 2, 3, 4])), { right: new Set([2, 4]), left: new Set([1, 3]) }) // refinements - const x: Set = new Set([1, 'a', 2]) const isNumber = (u: string | number): u is number => typeof u === 'number' - const actual = partition(x, isNumber) + const actual = partition(isNumber)(new Set([1, 'a', 2])) assert.deepStrictEqual(actual, { left: new Set(['a']), right: new Set([1, 2]) @@ -127,12 +125,12 @@ describe('Set', () => { }) it('partitionMap', () => { - assert.deepStrictEqual(partitionMap(eqNumber, eqString)(new Set([]), left), { + assert.deepStrictEqual(partitionMap(eqNumber, eqString)((n: number) => left(n))(new Set([])), { left: new Set([]), right: new Set([]) }) assert.deepStrictEqual( - partitionMap(eqNumber, eqString)(new Set([1, 2, 3]), x => (x % 2 === 0 ? left(x) : right(`${x}`))), + partitionMap(eqNumber, eqString)((n: number) => (n % 2 === 0 ? left(n) : right(`${n}`)))(new Set([1, 2, 3])), { left: new Set([2]), right: new Set(['1', '3']) @@ -141,9 +139,9 @@ describe('Set', () => { const SL = getStructEq({ value: eqNumber }) const SR = getStructEq({ value: eqString }) assert.deepStrictEqual( - partitionMap(SL, SR)(new Set([{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }]), x => + partitionMap(SL, SR)((x: { value: number }) => x.value % 2 === 0 ? left({ value: 2 }) : right({ value: 'odd' }) - ), + )(new Set([{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }])), { left: new Set([{ value: 2 }]), right: new Set([{ value: 'odd' }]) @@ -170,13 +168,13 @@ describe('Set', () => { }) it('reduce', () => { - assert.deepStrictEqual(reduce(ordNumber)(new Set([1, 2, 3]), '', (b, a) => b + a), '123') - assert.deepStrictEqual(reduce(ordNumber)(new Set([3, 2, 1]), '', (b, a) => b + a), '123') + assert.deepStrictEqual(reduce(ordNumber)('', (b, a) => b + a)(new Set([1, 2, 3])), '123') + assert.deepStrictEqual(reduce(ordNumber)('', (b, a) => b + a)(new Set([3, 2, 1])), '123') }) it('foldMap', () => { - assert.deepStrictEqual(foldMap(ordNumber, getMonoid())(new Set([1, 2, 3]), a => [a]), [1, 2, 3]) - assert.deepStrictEqual(foldMap(ordNumber, getMonoid())(new Set([3, 2, 1]), a => [a]), [1, 2, 3]) + assert.deepStrictEqual(foldMap(ordNumber, getMonoid())(a => [a])(new Set([1, 2, 3])), [1, 2, 3]) + assert.deepStrictEqual(foldMap(ordNumber, getMonoid())(a => [a])(new Set([3, 2, 1])), [1, 2, 3]) }) it('singleton', () => { @@ -185,14 +183,14 @@ describe('Set', () => { it('insert', () => { const x = new Set([1, 2]) - assert.deepStrictEqual(insert(eqNumber)(3, x), new Set([1, 2, 3])) + assert.deepStrictEqual(insert(eqNumber)(3)(x), new Set([1, 2, 3])) // should return the same ference if the element is already a member - assert.strictEqual(insert(eqNumber)(2, x), x) + assert.strictEqual(insert(eqNumber)(2)(x), x) }) it('remove', () => { - assert.deepStrictEqual(remove(eqNumber)(3, new Set([1, 2])), new Set([1, 2])) - assert.deepStrictEqual(remove(eqNumber)(1, new Set([1, 2])), new Set([2])) + assert.deepStrictEqual(remove(eqNumber)(3)(new Set([1, 2])), new Set([1, 2])) + assert.deepStrictEqual(remove(eqNumber)(1)(new Set([1, 2])), new Set([2])) }) it('fromArray', () => { @@ -236,12 +234,15 @@ describe('Set', () => { it('filterMap', () => { assert.deepStrictEqual( - filterMap(eqNumber)(new Set(['a', 'bb', 'ccc']), s => (s.length > 1 ? optionSome(s.length) : none)), + filterMap(eqNumber)((s: string) => (s.length > 1 ? optionSome(s.length) : none))(new Set(['a', 'bb', 'ccc'])), new Set([2, 3]) ) type R = { id: string } const S: Eq = contramap(eqString, x => x.id) - assert.deepStrictEqual(filterMap(S)(new Set([{ id: 'a' }, { id: 'a' }]), optionSome), new Set([{ id: 'a' }])) + assert.deepStrictEqual( + filterMap(S)((x: { id: string }) => optionSome(x))(new Set([{ id: 'a' }, { id: 'a' }])), + new Set([{ id: 'a' }]) + ) }) it('getShow', () => {