diff --git a/src/cata.js b/src/cata.js new file mode 100644 index 0000000000..af2f27591e --- /dev/null +++ b/src/cata.js @@ -0,0 +1,26 @@ +import { invoker } from 'ramda'; + +/** + * The catamorphism for either. If the either is right than the right function will be executed with + * the right value and the value of the function returned. Otherwise the left function + * will be called with the left value. + * + * @func cata + * @memberOf RA + * @since {@link https://char0n.github.io/ramda-adjunct/1.4.0|v1.4.0} + * @category Function + * @sig (a -> b) -> (a -> c) -> Either a -> b | c + * @param {*} val The value to test + * @return {*} + * @see {@link RA.isNotArray|isNotArray} + * @example + * + * const eitherR = Either.Right(1); + * const eitherL = Either.Left(2); + * + * RA.cata(identity, identity, eitherR); //=> 1 + * RA.cata(identity, identity, eitherL); //=> 2 + */ +const cata = invoker(2, 'cata'); + +export default cata; diff --git a/src/index.d.ts b/src/index.d.ts index 60ac23edba..c2b56ff91c 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -2,8 +2,16 @@ declare var RA: RamdaAdjunct.Static; declare namespace RamdaAdjunct { - interface Apply { - app: Function; + interface Functor { + map(fn: (t: T) => U): Functor; + } + + interface Apply extends Functor { + ap(fn: Apply<(t: T) => U>): Apply; + } + + interface Catamorphism { + cata(leftFn: (v: T1) => T, rightFn: (v: T1) => T): T; } interface Variadic { @@ -236,13 +244,29 @@ declare namespace RamdaAdjunct { * "lifts" a function to be the specified arity, so that it may "map over" objects that satisfy * the Apply spec of fantasy land. */ - liftFN(arity: number, fn: Variadic): Apply + liftFN(arity: number, fn: Variadic, T>): Apply /** * "lifts" a function of arity > 1 so that it may "map over" objects that satisfy * the Apply spec of fantasy land. */ - liftF(fn: Variadic): Apply + liftF(fn: Variadic, T>): Apply + + /** + * The catamorphism for either. If the either is right than the right function will be executed with + * the right value and the value of the function returned. Otherwise the left function + * will be called with the left value. + */ + cata(leftFn: (leftValue: V1) => T1, rightFn: (rightValue: V2) => T2, either: Catamorphism): T1|T2; + cata(leftFn: (leftValue: V1) => T1, rightFn: (rightValue: V2) => T2): { + (either: Catamorphism): T1|T2; + }; + cata(leftFn: (leftValue: V1) => T1): { + (rightFn: (rightValue: V2) => T1, either: Catamorphism): T1|T2; + (rightFn: (rightValue: V2) => T1): { + (either: Catamorphism): T1|T2; + } + } } } diff --git a/src/index.js b/src/index.js index 2a8b013cbc..27b1244b5f 100644 --- a/src/index.js +++ b/src/index.js @@ -40,6 +40,7 @@ import stubUndefined from './stubUndefined'; import noop from './noop'; import liftFN from './liftFN'; import liftF from './liftF'; +import cata from './cata'; // List import pickIndexes from './pickIndexes'; import list from './list'; @@ -90,6 +91,7 @@ export { default as stubUndefined } from './stubUndefined'; export { default as noop } from './noop'; export { default as liftFN } from './liftFN'; export { default as liftF } from './liftF'; +export { default as cata } from './cata'; // List export { default as pickIndexes } from './pickIndexes'; export { default as list } from './list'; @@ -144,6 +146,7 @@ const RA = { noop, liftFN, liftF, + cata, // List pickIndexes, list, diff --git a/test/cata.js b/test/cata.js new file mode 100644 index 0000000000..120701cae7 --- /dev/null +++ b/test/cata.js @@ -0,0 +1,31 @@ +import { Either } from 'monet'; +import { identity } from 'ramda'; +import chai from 'chai'; + +import RA from '../src/index'; +import eq from './shared/eq'; + +describe('cata', function() { + const eitherR = Either.Right(1); + const eitherL = Either.Left(2); + + it('tests an Either for catamorphism', function() { + eq(RA.cata(identity, identity, eitherR), 1); + eq(RA.cata(identity, identity, eitherL), 2); + }); + + it('test currying', function() { + eq(RA.cata(identity)(identity)(eitherR), 1); + eq(RA.cata(identity, identity)(eitherL), 2); + }); + + it('tests left for catamorphism without functions', function() { + chai.assert.throws(RA.cata.bind(null, null, identity, eitherL), TypeError); + eq(RA.cata(identity, null, eitherL), 2); + }); + + it('tests right for catamorphism without functions', function() { + chai.assert.throws(RA.cata.bind(null, identity, null, eitherR), TypeError); + eq(RA.cata(null, identity, eitherR), 1); + }); +});