From 3284938baa782bb8760e7b75dfd41955c6157e4e Mon Sep 17 00:00:00 2001 From: Kirill Agalakov Date: Mon, 25 Jun 2018 11:30:08 +0300 Subject: [PATCH] Feature/filterable (#492) * feature: Filterable // typeclass * feature: Filterable // use .prettierrc/.prettierignore to support WS watchers * feature: Filterable // default implementations * feature: Filterable // default implementations + tests * feature: Filterable // default implementations * feature: Filterable // remove CompactableA, Compactable1A * feature: Filterable // postreview --- .prettierignore | 6 + .prettierrc | 6 + package.json | 4 +- src/Compactable.ts | 110 ++++++++------ src/Filterable.ts | 338 ++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 2 + test/Compactable.ts | 88 ++++++------ test/Filterable.ts | 133 +++++++++++++++++ test/Option.ts | 4 +- 9 files changed, 607 insertions(+), 84 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 src/Filterable.ts create mode 100644 test/Filterable.ts diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..126d17fe4 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +/lib +/docs +/docs-generator +/perf +/node_modules +/typings-checker \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..a5187b8f7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": false, + "singleQuote": true, + "printWidth": 120, + "parser": "typescript" +} \ No newline at end of file diff --git a/package.json b/package.json index 0e023e056..8ce38e4b8 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "lint": "tslint -p tsconfig.json src/**/*.ts test/**/*.ts examples/**/*.ts exercises/**/*.ts fantas-eel-and-specification/**/*.ts", "jest": "jest --ci", "jest-coverage": "jest --ci --coverage", - "prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --list-different \"{src,test,examples,exercises}/**/*.ts\"", - "fix-prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --write \"{src,test,examples,exercises}/**/*.ts\"", + "prettier": "prettier --list-different \"./{src,test,examples,exercises}/**/*.ts\"", + "fix-prettier": "prettier --write \"./{src,test,examples,exercises}/**/*.ts\"", "typings": "typings-checker --project ./typings-checker/tsconfig.json ./typings-checker/index.ts", "test": "npm run lint && npm run prettier && npm run typings && npm run jest", "clean": "rimraf lib/*", diff --git a/src/Compactable.ts b/src/Compactable.ts index c1c8fe5bf..1fb0baf2d 100644 --- a/src/Compactable.ts +++ b/src/Compactable.ts @@ -2,6 +2,8 @@ import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT' import { fromEither, Option } from './Option' import { Either, fromOption } from './Either' import { Functor, Functor1, Functor2, Functor2C, Functor3, Functor3C } from './Functor' +import { Filterable, Filterable1, Filterable2, Filterable2C, Filterable3, Filterable3C } from './Filterable' +import { identity } from './function' /** * `Separated` type which holds `left` and `right` parts @@ -35,19 +37,6 @@ export interface Compactable { readonly separate: (fa: HKT>) => Separated, HKT> } -/** - * @see Compactable - * @since 1.7.0 - */ -export interface CompactableA { - readonly URI: F - readonly _A: A - readonly _RL: RL - readonly _RR: RR - readonly compact: (fa: HKT>) => HKT - readonly separate: (fa: HKT>) => Separated, HKT> -} - /** * @see Compactable * @since 1.7.0 @@ -58,19 +47,6 @@ export interface Compactable1 { readonly separate: (fa: Type>) => Separated, Type> } -/** - * @see Compactable - * @since 1.7.0 - */ -export interface Compactable1A { - readonly URI: F - readonly _A: A - readonly _RL: RL - readonly _RR: RR - readonly compact: (fa: Type>) => Type - readonly separate: (fa: Type>) => Separated, Type> -} - /** * @see Compactable * @since 1.7.0 @@ -119,51 +95,105 @@ export interface Compactable3C { * @function * @since 1.7.0 */ -export function compactDefault( +export function getCompactFromSeparate( F: Functor3C & Pick, 'separate'> ): Compactable3C['compact'] -export function compactDefault( +export function getCompactFromSeparate( F: Functor3 & Pick, 'separate'> ): Compactable3['compact'] -export function compactDefault( +export function getCompactFromSeparate( F: Functor2C & Pick, 'separate'> ): Compactable2C['compact'] -export function compactDefault( +export function getCompactFromSeparate( F: Functor2 & Pick, 'separate'> ): Compactable2['compact'] -export function compactDefault( +export function getCompactFromSeparate( F: Functor1 & Pick, 'separate'> ): Compactable1['compact'] -export function compactDefault(F: Functor & Pick, 'separate'>): Compactable['compact'] -export function compactDefault(F: Functor & Pick, 'separate'>): Compactable['compact'] { +export function getCompactFromSeparate(F: Functor & Pick, 'separate'>): Compactable['compact'] +export function getCompactFromSeparate(F: Functor & Pick, 'separate'>): Compactable['compact'] { return foa => F.separate(F.map(foa, fromOption(null))).right } +/** + * Gets default implementation of {@link Compactable.compact} using {@link Filterable.filterMap} + * @function + * @since 1.7.0 + */ +export function getCompactFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Compactable3C['compact'] +export function getCompactFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Compactable3['compact'] +export function getCompactFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Compactable2C['compact'] +export function getCompactFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Compactable2['compact'] +export function getCompactFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Compactable1['compact'] +export function getCompactFromFilterMap(F: Pick, 'URI' | 'filterMap'>): Compactable['compact'] +export function getCompactFromFilterMap(F: Pick, 'URI' | 'filterMap'>): Compactable['compact'] { + return fa => F.filterMap(fa, identity) +} + /** * Gets default implementation of {@link Compactable.separate} using {@link Compactable.compact} * @function * @since 1.7.0 */ -export function separateDefault( +export function getSeparateFromCompact( F: Functor3C & Pick, 'compact'> ): Compactable3C['separate'] -export function separateDefault( +export function getSeparateFromCompact( F: Functor3 & Pick, 'compact'> ): Compactable3['separate'] -export function separateDefault( +export function getSeparateFromCompact( F: Functor2C & Pick, 'compact'> ): Compactable2C['separate'] -export function separateDefault( +export function getSeparateFromCompact( F: Functor2 & Pick, 'compact'> ): Compactable2['separate'] -export function separateDefault( +export function getSeparateFromCompact( F: Functor1 & Pick, 'compact'> ): Compactable1['separate'] -export function separateDefault(F: Functor & Pick, 'compact'>): Compactable['separate'] -export function separateDefault(F: Functor & Pick, 'compact'>): Compactable['separate'] { +export function getSeparateFromCompact(F: Functor & Pick, 'compact'>): Compactable['separate'] +export function getSeparateFromCompact(F: Functor & Pick, 'compact'>): Compactable['separate'] { return fe => { const left = F.compact(F.map(fe, e => fromEither(e.swap()))) const right = F.compact(F.map(fe, fromEither)) return { left, right } } } + +/** + * Gets default implementation of {@link Compactable.separate} using {@link Filterable.partitionMap} + * @function + * @since 1.7.0 + */ +export function getSeparateFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Compactable3C['separate'] +export function getSeparateFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Compactable3['separate'] +export function getSeparateFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Compactable2C['separate'] +export function getSeparateFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Compactable2['separate'] +export function getSeparateFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Compactable1['separate'] +export function getSeparateFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Compactable['separate'] +export function getSeparateFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Compactable['separate'] { + return fa => F.partitionMap(fa, identity) +} diff --git a/src/Filterable.ts b/src/Filterable.ts new file mode 100644 index 000000000..0a63fc77a --- /dev/null +++ b/src/Filterable.ts @@ -0,0 +1,338 @@ +import { Functor, Functor1, Functor2, Functor2C, Functor3, Functor3C } from './Functor' +import { + Compactable, + Compactable1, + Compactable2, + Compactable2C, + Compactable3, + Compactable3C, + Separated +} from './Compactable' +import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT' +import { Either, fromPredicate as fromPredicateEither } from './Either' +import { identity, not, Predicate } from './function' +import { Option, fromPredicate as fromPredicateOption } from './Option' + +/** + * @typeclass + * `Filterable` represents data structures which can be _partitioned_/_filtered_. + * - {@link partitionMap} + * - {@link partition} + * - {@link filterMap} + * - {@link filter} + * + * @see https://github.com/LiamGoodacre/purescript-filterable/blob/master/src/Data/Filterable.purs + * @since 1.7.0 + */ +export interface Filterable extends Functor, Compactable { + /** + * Partition a data structure based on an either predicate. + * @since 1.7.0 + */ + readonly partitionMap: (fa: HKT, f: (a: A) => Either) => Separated, HKT> + /** + * Partition a data structure based on boolean predicate. + * @since 1.7.0 + */ + readonly partition: (fa: HKT, p: Predicate) => Separated, HKT> + /** + * Map over a data structure and filter based on a maybe. + * @since 1.7.0 + */ + readonly filterMap: (fa: HKT, f: (a: A) => Option) => HKT + /** + * Filter a data structure based on a boolean. + * @since 1.7.0 + */ + readonly filter: (fa: HKT, p: Predicate) => HKT +} + +/** + * @since 1.7.0 + * @see Filterable + */ +export interface Filterable1 extends Functor1, Compactable1 { + readonly partitionMap: (fa: Type, f: (a: A) => Either) => Separated, Type> + readonly partition: (fa: Type, p: Predicate) => Separated, Type> + readonly filterMap: (fa: Type, f: (a: A) => Option) => Type + readonly filter: (fa: Type, p: Predicate) => Type +} + +/** + * @since 1.7.0 + * @see Filterable + */ +export interface Filterable2 extends Functor2, Compactable2 { + readonly partitionMap: ( + fa: Type2, + f: (a: A) => Either + ) => Separated, Type2> + readonly partition: (fa: Type2, p: Predicate) => Separated, Type2> + readonly filterMap: (fa: Type2, f: (a: A) => Option) => Type2 + readonly filter: (fa: Type2, p: Predicate) => Type2 +} + +/** + * @since 1.7.0 + * @see Filterable + */ +export interface Filterable2C extends Functor2C, Compactable2C { + readonly partitionMap: ( + fa: Type2, + f: (a: A) => Either + ) => Separated, Type2> + readonly partition: (fa: Type2, p: Predicate) => Separated, Type2> + readonly filterMap: (fa: Type2, f: (a: A) => Option) => Type2 + readonly filter: (fa: Type2, p: Predicate) => Type2 +} + +/** + * @since 1.7.0 + * @see Filterable + */ +export interface Filterable3 extends Functor3, Compactable3 { + readonly partitionMap: ( + fa: Type3, + f: (a: A) => Either + ) => Separated, Type3> + readonly partition: ( + fa: Type3, + p: Predicate + ) => Separated, Type3> + readonly filterMap: (fa: Type3, f: (a: A) => Option) => Type3 + readonly filter: (fa: Type3, p: Predicate) => Type3 +} + +/** + * @since 1.7.0 + * @see Filterable + */ +export interface Filterable3C extends Functor3C, Compactable3C { + readonly partitionMap: ( + fa: Type3, + f: (a: A) => Either + ) => Separated, Type3> + readonly partition: (fa: Type3, p: Predicate) => Separated, Type3> + readonly filterMap: (fa: Type3, f: (a: A) => Option) => Type3 + readonly filter: (fa: Type3, p: Predicate) => Type3 +} + +/** + * Gets default implementation of {@link Filterable.partitionMap} using {@link Compactable.separate} + * @function + * @since 1.7.0 + */ +export function getPartitionMapFromSeparate( + F: Functor3C & Pick, 'separate'> +): Filterable3C['partitionMap'] +export function getPartitionMapFromSeparate( + F: Functor3 & Pick, 'separate'> +): Filterable3['partitionMap'] +export function getPartitionMapFromSeparate( + F: Functor2C & Pick, 'separate'> +): Filterable2C['partitionMap'] +export function getPartitionMapFromSeparate( + F: Functor2 & Pick, 'separate'> +): Filterable2['partitionMap'] +export function getPartitionMapFromSeparate( + F: Functor1 & Pick, 'separate'> +): Filterable1['partitionMap'] +export function getPartitionMapFromSeparate( + F: Functor & Pick, 'separate'> +): Filterable['partitionMap'] +export function getPartitionMapFromSeparate( + F: Functor & Pick, 'separate'> +): Filterable['partitionMap'] { + return (fa, f) => F.separate(F.map(fa, f)) +} + +/** + * Gets default implementation of {@link Filterable.partition} using {@link Filterable.partitionMap} + * @function + * @since 1.7.0 + */ +export function getPartitionFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable3C['partition'] +export function getPartitionFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable3['partition'] +export function getPartitionFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable2C['partition'] +export function getPartitionFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable2['partition'] +export function getPartitionFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable1['partition'] +export function getPartitionFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable['partition'] +export function getPartitionFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable['partition'] { + return (fa, p) => F.partitionMap(fa, fromPredicateEither(p, identity)) +} + +/** + * Gets default implementation of {@link Filterable.partition} using {@link Filterable.filter} + * @function + * @since 1.7.0 + */ +export function getPartitionFromFilter( + F: Pick, 'URI' | 'filter'> +): Filterable3C['partition'] +export function getPartitionFromFilter( + F: Pick, 'URI' | 'filter'> +): Filterable3['partition'] +export function getPartitionFromFilter( + F: Pick, 'URI' | 'filter'> +): Filterable2C['partition'] +export function getPartitionFromFilter( + F: Pick, 'URI' | 'filter'> +): Filterable2['partition'] +export function getPartitionFromFilter( + F: Pick, 'URI' | 'filter'> +): Filterable1['partition'] +export function getPartitionFromFilter(F: Pick, 'URI' | 'filter'>): Filterable['partition'] +export function getPartitionFromFilter(F: Pick, 'URI' | 'filter'>): Filterable['partition'] { + return (fa, p) => ({ + left: F.filter(fa, not(p)), + right: F.filter(fa, p) + }) +} + +/** + * Gets default implementation of {@link Filterable.partition} using {@Filterable.filterMap} + * @function + * @since 1.7.0 + */ +export function getPartitionFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable3C['partition'] +export function getPartitionFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable3['partition'] +export function getPartitionFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable2C['partition'] +export function getPartitionFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable2['partition'] +export function getPartitionFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable1['partition'] +export function getPartitionFromFilterMap(F: Pick, 'URI' | 'filterMap'>): Filterable['partition'] +export function getPartitionFromFilterMap(F: Pick, 'URI' | 'filterMap'>): Filterable['partition'] { + return (fa, p) => ({ + left: F.filterMap(fa, fromPredicateOption(not(p))), + right: F.filterMap(fa, fromPredicateOption(p)) + }) +} + +/** + * Gets default implementation of {@link Filterable.filterMap} using {@link Compactable.compact} + * @function + * @since 1.7.0 + */ +export function getFilterMapFromCompact( + F: Functor3C & Pick, 'compact'> +): Filterable3C['filterMap'] +export function getFilterMapFromCompact( + F: Functor3 & Pick, 'compact'> +): Filterable3['filterMap'] +export function getFilterMapFromCompact( + F: Functor2C & Pick, 'compact'> +): Filterable2C['filterMap'] +export function getFilterMapFromCompact( + F: Functor2 & Pick, 'compact'> +): Filterable2['filterMap'] +export function getFilterMapFromCompact( + F: Functor1 & Pick, 'compact'> +): Filterable1['filterMap'] +export function getFilterMapFromCompact(F: Functor & Pick, 'compact'>): Filterable['filterMap'] +export function getFilterMapFromCompact( + F: Functor & Pick, 'compact'> +): Filterable['filterMap'] { + return (fa, f) => F.compact(F.map(fa, f)) +} + +/** + * Gets default implementation of {@link Filterable.filter} using {@link Filterable.filterMap} + * @function + * @since 1.7.0 + */ +export function getFilterFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable3C['filter'] +export function getFilterFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable3['filter'] +export function getFilterFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable2C['filter'] +export function getFilterFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable2['filter'] +export function getFilterFromFilterMap( + F: Pick, 'URI' | 'filterMap'> +): Filterable1['filter'] +export function getFilterFromFilterMap(F: Pick, 'URI' | 'filterMap'>): Filterable['filter'] +export function getFilterFromFilterMap(F: Pick, 'URI' | 'filterMap'>): Filterable['filter'] { + return (fa, p) => F.filterMap(fa, fromPredicateOption(p)) +} + +/** + * Gets default implementation of {@link Filterable.filter} using {@link Filterable.partition} + * @function + * @since 1.7.0 + */ +export function getFilterFromPartition( + F: Functor3C & Pick, 'URI' | 'partition'> +): Filterable3C['filter'] +export function getFilterFromPartition( + F: Functor3 & Pick, 'URI' | 'partition'> +): Filterable3['filter'] +export function getFilterFromPartition( + F: Functor2C & Pick, 'URI' | 'partition'> +): Filterable2C['filter'] +export function getFilterFromPartition( + F: Functor2 & Pick, 'URI' | 'partition'> +): Filterable2['filter'] +export function getFilterFromPartition( + F: Functor1 & Pick, 'URI' | 'partition'> +): Filterable1['filter'] +export function getFilterFromPartition( + F: Functor & Pick, 'URI' | 'partition'> +): Filterable['filter'] +export function getFilterFromPartition( + F: Functor & Pick, 'URI' | 'partition'> +): Filterable['filter'] { + return (fa, p) => F.partition(fa, p).right +} + +/** + * Gets default implementation of {@link Filterable.filter} using {@link Filterable.partitionMap} + * @function + * @since 1.7.0 + */ +export function getFilterFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable3C['filter'] +export function getFilterFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable3['filter'] +export function getFilterFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable2C['filter'] +export function getFilterFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable2['filter'] +export function getFilterFromPartitionMap( + F: Pick, 'URI' | 'partitionMap'> +): Filterable1['filter'] +export function getFilterFromPartitionMap(F: Pick, 'URI' | 'partitionMap'>): Filterable['filter'] +export function getFilterFromPartitionMap(F: Pick, 'URI' | 'partitionMap'>): Filterable['filter'] { + return (fa, p) => F.partitionMap(fa, fromPredicateEither(p, identity)).right +} diff --git a/src/index.ts b/src/index.ts index b93691e9c..934fdfa0a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -150,3 +150,5 @@ import * as writer from './Writer' export { writer } import * as compactable from './Compactable' export { compactable } +import * as filterable from './Filterable' +export { filterable } diff --git a/test/Compactable.ts b/test/Compactable.ts index 465bac5ef..a9e32e82d 100644 --- a/test/Compactable.ts +++ b/test/Compactable.ts @@ -1,51 +1,57 @@ import * as assert from 'assert' -import { Either, left, right } from '../src/Either' -import { none, some, Option, option } from '../src/Option' -import { compactDefault, Separated, separateDefault } from '../src/Compactable' -import { identity } from '../src/function' +import { left, right } from '../src/Either' +import { none, some } from '../src/Option' +import { + getCompactFromFilterMap, + getCompactFromSeparate, + getSeparateFromCompact, + getSeparateFromPartitionMap +} from '../src/Compactable' +import { array, mapOption, partitionMap } from '../src/Array' describe('Compactable', () => { - const separate = (fa: Option>): Separated, Option> => - fa.foldL( - () => ({ - left: none, - right: none - }), - e => - e.fold, Option>>( - l => ({ - left: some(l), - right: none - }), - r => ({ - left: none, - right: some(r) - }) - ) - ) - - const compact = (fa: Option>): Option => fa.chain(identity) - - it('compactDefault', () => { - const F = { - ...option, + it('getCompactFromSeparate', () => { + const { URI, map, separate } = array + const compactF = getCompactFromSeparate({ + URI, + map, separate - } - const compactDefaultF = compactDefault(F) - assert.deepEqual(compactDefaultF(none), compact(none)) - assert.deepEqual(compactDefaultF(some(none)), compact(some(none))) - assert.deepEqual(compactDefaultF(some(some(123))), compact(some(some(123)))) + }) + assert.deepEqual(compactF([]), []) + assert.deepEqual(compactF([none]), []) + assert.deepEqual(compactF([none, some(1)]), [1]) + }) + + it('getCompactFromFilterMap', () => { + const compactF = getCompactFromFilterMap({ + URI: array.URI, + filterMap: mapOption + }) + assert.deepEqual(compactF([]), []) + assert.deepEqual(compactF([none]), []) + assert.deepEqual(compactF([none, some(1)]), [1]) }) - it('separateDefault', () => { - const F = { - ...option, + it('getSeparateFromCompact', () => { + const { URI, map, compact } = array + const separateF = getSeparateFromCompact({ + URI, + map, compact - } + }) + assert.deepEqual(separateF([]), { left: [], right: [] }) + assert.deepEqual(separateF([left(1)]), { left: [1], right: [] }) + assert.deepEqual(separateF([left(1), right(3)]), { left: [1], right: [3] }) + }) + + it('getSeparateFromPartitionMap', () => { + const separateF = getSeparateFromPartitionMap({ + URI: array.URI, + partitionMap + }) - const separateDefaultF = separateDefault(F) - assert.deepEqual(separateDefaultF(none), separate(none)) - assert.deepEqual(separateDefaultF(some(left('123'))), separate(some(left('123')))) - assert.deepEqual(separateDefaultF(some(right('123'))), separate(some(right('123')))) + assert.deepEqual(separateF([]), { left: [], right: [] }) + assert.deepEqual(separateF([left(1)]), { left: [1], right: [] }) + assert.deepEqual(separateF([left(1), right(3)]), { left: [1], right: [3] }) }) }) diff --git a/test/Filterable.ts b/test/Filterable.ts new file mode 100644 index 000000000..f38c58114 --- /dev/null +++ b/test/Filterable.ts @@ -0,0 +1,133 @@ +import * as assert from 'assert' +import { + getFilterFromFilterMap, + getFilterFromPartition, + getFilterFromPartitionMap, + getFilterMapFromCompact, + getPartitionFromFilter, + getPartitionFromFilterMap, + getPartitionFromPartitionMap, + getPartitionMapFromSeparate +} from '../src/Filterable' +import { array, filter } from '../src/Array' +import { left, right } from '../src/Either' +import { none, some } from '../src/Option' + +describe('Filterable', () => { + const p = (n: number) => n > 2 + + it('getPartitionMapFromSeparate', () => { + const { URI, map, separate } = array + const F = { + URI, + map, + separate + } + const partitionMapF = getPartitionMapFromSeparate(F) + const f = (n: number) => (p(n) ? right(n + 1) : left(n - 1)) + assert.deepEqual(partitionMapF([], f), { left: [], right: [] }) + assert.deepEqual(partitionMapF([1, 3], f), { left: [0], right: [4] }) + }) + + it('getPartitionFromPartitionMap', () => { + const { URI, map, separate } = array + + const partitionMapF = getPartitionMapFromSeparate({ + URI, + map, + separate + }) + + const partitionF = getPartitionFromPartitionMap({ + URI, + partitionMap: partitionMapF + }) + + assert.deepEqual(partitionF([], p), { left: [], right: [] }) + assert.deepEqual(partitionF([1, 3], p), { left: [1], right: [3] }) + }) + + it('getPartitionFromFilter', () => { + const { URI } = array + const F = { + URI, + filter + } + const partitionF = getPartitionFromFilter(F) + assert.deepEqual(partitionF([], p), { left: [], right: [] }) + assert.deepEqual(partitionF([1, 3], p), { left: [1], right: [3] }) + }) + + it('getPartitionFromFilterMap', () => { + const { URI, map, compact } = array + const filterMapF = getFilterMapFromCompact({ + URI, + map, + compact + }) + const partitionF = getPartitionFromFilterMap({ + URI, + filterMap: filterMapF + }) + + assert.deepEqual(partitionF([], p), { left: [], right: [] }) + assert.deepEqual(partitionF([1, 3], p), { left: [1], right: [3] }) + }) + + it('getFilterMapFromCompact', () => { + const { URI, map, compact } = array + const F = { + URI, + map, + compact + } + const filterMapF = getFilterMapFromCompact(F) + const f = (n: number) => (p(n) ? some(n + 1) : none) + assert.deepEqual(filterMapF([], f), []) + assert.deepEqual(filterMapF([1, 3], f), [4]) + }) + + it('getFilterFromFilterMap', () => { + const { URI, map, compact } = array + const filterMapF = getFilterMapFromCompact({ + URI, + map, + compact + }) + const filterF = getFilterFromFilterMap({ + URI, + filterMap: filterMapF + }) + + assert.deepEqual(filterF([], p), []) + assert.deepEqual(filterF([1, 3], p), [3]) + }) + + it('getFilterFromPartition', () => { + const { URI, map } = array + const partition = getPartitionFromFilter({ URI, filter }) + const filterF = getFilterFromPartition({ URI, map, partition }) + assert.deepEqual(filterF([], p), []) + assert.deepEqual(filterF([1, 3], p), [3]) + }) + + it('getFilterFromPartitionMap', () => { + const { URI, map, separate } = array + + const partitionMapF = getPartitionMapFromSeparate({ + URI, + map, + separate + }) + + const filterF = getFilterFromPartitionMap({ + URI, + partitionMap: partitionMapF + }) + + const p = (n: number) => n > 2 + + assert.deepEqual(filterF([], p), []) + assert.deepEqual(filterF([1, 3], p), [3]) + }) +}) diff --git a/test/Option.ts b/test/Option.ts index 926c2bd23..3965fd648 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -25,6 +25,8 @@ import { setoidNumber } from '../src/Setoid' import { traverse } from '../src/Traversable' import { identity } from '../src/function' +const p = (n: number): boolean => n > 2 + describe('Option', () => { it('fold', () => { const f = 'none' @@ -180,7 +182,7 @@ describe('Option', () => { }) it('fromPredicate', () => { - const f = fromPredicate((n: number) => n > 2) + const f = fromPredicate(p) assert.deepEqual(f(1), none) assert.deepEqual(f(3), some(3)) })