import { fromEquals } from './Eq'; import { fromOption as fromOption_, fromOptionK as fromOptionK_, fromPredicate as fromPredicate_ } from './FromEither'; import { identity, pipe } from './function'; import { flap as flap_ } from './Functor'; import * as _ from './internal'; // ------------------------------------------------------------------------------------- // refinements // ------------------------------------------------------------------------------------- /** * Returns `true` if the these is an instance of `Left`, `false` otherwise * * @category refinements * @since 2.0.0 */ export var isLeft = function (fa) { return fa._tag === 'Left'; }; /** * Returns `true` if the these is an instance of `Right`, `false` otherwise * * @category refinements * @since 2.0.0 */ export var isRight = function (fa) { return fa._tag === 'Right'; }; /** * Returns `true` if the these is an instance of `Both`, `false` otherwise * * @category refinements * @since 2.0.0 */ export function isBoth(fa) { return fa._tag === 'Both'; } // ------------------------------------------------------------------------------------- // constructors // ------------------------------------------------------------------------------------- /** * @category constructors * @since 2.0.0 */ export function left(left) { return { _tag: 'Left', left: left }; } /** * @category constructors * @since 2.0.0 */ export function right(right) { return { _tag: 'Right', right: right }; } /** * @category constructors * @since 2.0.0 */ export function both(left, right) { return { _tag: 'Both', left: left, right: right }; } /** * Less strict version of [`match`](#match). * * The `W` suffix (short for **W**idening) means that the handler return types will be merged. * * @category pattern matching * @since 2.10.0 */ export var matchW = function (onLeft, onRight, onBoth) { return function (fa) { switch (fa._tag) { case 'Left': return onLeft(fa.left); case 'Right': return onRight(fa.right); case 'Both': return onBoth(fa.left, fa.right); } }; }; /** * Alias of [`matchW`](#matchw). * * @category pattern matching * @since 2.10.0 */ export var foldW = matchW; /** * @category pattern matching * @since 2.10.0 */ export var match = matchW; /** * Alias of [`match`](#match). * * @category pattern matching * @since 2.0.0 */ export var fold = match; /** * @since 2.4.0 */ export var swap = match(right, left, function (e, a) { return both(a, e); }); /** * @category instances * @since 2.0.0 */ export function getShow(SE, SA) { return { show: match(function (l) { return "left(".concat(SE.show(l), ")"); }, function (a) { return "right(".concat(SA.show(a), ")"); }, function (l, a) { return "both(".concat(SE.show(l), ", ").concat(SA.show(a), ")"); }) }; } /** * @category instances * @since 2.0.0 */ export function getEq(EE, EA) { return fromEquals(function (x, y) { return isLeft(x) ? isLeft(y) && EE.equals(x.left, y.left) : isRight(x) ? isRight(y) && EA.equals(x.right, y.right) : isBoth(y) && EE.equals(x.left, y.left) && EA.equals(x.right, y.right); }); } /** * @category instances * @since 2.0.0 */ export function getSemigroup(SE, SA) { return { concat: function (x, y) { return isLeft(x) ? isLeft(y) ? left(SE.concat(x.left, y.left)) : isRight(y) ? both(x.left, y.right) : both(SE.concat(x.left, y.left), y.right) : isRight(x) ? isLeft(y) ? both(y.left, x.right) : isRight(y) ? right(SA.concat(x.right, y.right)) : both(y.left, SA.concat(x.right, y.right)) : isLeft(y) ? both(SE.concat(x.left, y.left), x.right) : isRight(y) ? both(x.left, SA.concat(x.right, y.right)) : both(SE.concat(x.left, y.left), SA.concat(x.right, y.right)); } }; } /** * @category instances * @since 2.10.0 */ export var getApply = function (S) { return ({ URI: URI, _E: undefined, map: _map, ap: function (fab, fa) { return isLeft(fab) ? isLeft(fa) ? left(S.concat(fab.left, fa.left)) : isRight(fa) ? left(fab.left) : left(S.concat(fab.left, fa.left)) : isRight(fab) ? isLeft(fa) ? left(fa.left) : isRight(fa) ? right(fab.right(fa.right)) : both(fa.left, fab.right(fa.right)) : isLeft(fa) ? left(S.concat(fab.left, fa.left)) : isRight(fa) ? both(fab.left, fab.right(fa.right)) : both(S.concat(fab.left, fa.left), fab.right(fa.right)); } }); }; /** * @category instances * @since 2.7.0 */ export function getApplicative(S) { var A = getApply(S); return { URI: URI, _E: undefined, map: _map, ap: A.ap, of: of }; } /** * @category instances * @since 2.10.0 */ export function getChain(S) { var A = getApply(S); var chain = function (ma, f) { if (isLeft(ma)) { return ma; } if (isRight(ma)) { return f(ma.right); } var fb = f(ma.right); return isLeft(fb) ? left(S.concat(ma.left, fb.left)) : isRight(fb) ? both(ma.left, fb.right) : both(S.concat(ma.left, fb.left), fb.right); }; return { URI: URI, _E: undefined, map: _map, ap: A.ap, chain: chain }; } /** * @category instances * @since 2.0.0 */ export function getMonad(S) { var C = getChain(S); return { URI: URI, _E: undefined, map: _map, of: of, ap: C.ap, chain: C.chain, throwError: left }; } /** * Returns an `E` value if possible * * @example * import { getLeft, left, right, both } from 'fp-ts/These' * import { none, some } from 'fp-ts/Option' * * assert.deepStrictEqual(getLeft(left('a')), some('a')) * assert.deepStrictEqual(getLeft(right(1)), none) * assert.deepStrictEqual(getLeft(both('a', 1)), some('a')) * * @category conversions * @since 2.0.0 */ export function getLeft(fa) { return isLeft(fa) ? _.some(fa.left) : isRight(fa) ? _.none : _.some(fa.left); } /** * Returns an `A` value if possible * * @example * import { getRight, left, right, both } from 'fp-ts/These' * import { none, some } from 'fp-ts/Option' * * assert.deepStrictEqual(getRight(left('a')), none) * assert.deepStrictEqual(getRight(right(1)), some(1)) * assert.deepStrictEqual(getRight(both('a', 1)), some(1)) * * @category conversions * @since 2.0.0 */ export function getRight(fa) { return isLeft(fa) ? _.none : isRight(fa) ? _.some(fa.right) : _.some(fa.right); } // TODO: make lazy in v3 /** * @example * import { leftOrBoth, left, both } from 'fp-ts/These' * import { none, some } from 'fp-ts/Option' * * assert.deepStrictEqual(leftOrBoth('a')(none), left('a')) * assert.deepStrictEqual(leftOrBoth('a')(some(1)), both('a', 1)) * * @category constructors * @since 2.0.0 */ export function leftOrBoth(e) { return function (ma) { return (_.isNone(ma) ? left(e) : both(e, ma.value)); }; } // TODO: make lazy in v3 /** * @example * import { rightOrBoth, right, both } from 'fp-ts/These' * import { none, some } from 'fp-ts/Option' * * assert.deepStrictEqual(rightOrBoth(1)(none), right(1)) * assert.deepStrictEqual(rightOrBoth(1)(some('a')), both('a', 1)) * * @category constructors * @since 2.0.0 */ export function rightOrBoth(a) { return function (me) { return (_.isNone(me) ? right(a) : both(me.value, a)); }; } /** * Returns the `E` value if and only if the value is constructed with `Left` * * @example * import { getLeftOnly, left, right, both } from 'fp-ts/These' * import { none, some } from 'fp-ts/Option' * * assert.deepStrictEqual(getLeftOnly(left('a')), some('a')) * assert.deepStrictEqual(getLeftOnly(right(1)), none) * assert.deepStrictEqual(getLeftOnly(both('a', 1)), none) * * @category conversions * @since 2.0.0 */ export function getLeftOnly(fa) { return isLeft(fa) ? _.some(fa.left) : _.none; } /** * Returns the `A` value if and only if the value is constructed with `Right` * * @example * import { getRightOnly, left, right, both } from 'fp-ts/These' * import { none, some } from 'fp-ts/Option' * * assert.deepStrictEqual(getRightOnly(left('a')), none) * assert.deepStrictEqual(getRightOnly(right(1)), some(1)) * assert.deepStrictEqual(getRightOnly(both('a', 1)), none) * * @category conversions * @since 2.0.0 */ export function getRightOnly(fa) { return isRight(fa) ? _.some(fa.right) : _.none; } /** * Takes a pair of `Option`s and attempts to create a `These` from them * * @example * import { fromOptions, left, right, both } from 'fp-ts/These' * import { none, some } from 'fp-ts/Option' * * assert.deepStrictEqual(fromOptions(none, none), none) * assert.deepStrictEqual(fromOptions(some('a'), none), some(left('a'))) * assert.deepStrictEqual(fromOptions(none, some(1)), some(right(1))) * assert.deepStrictEqual(fromOptions(some('a'), some(1)), some(both('a', 1))) * * @category conversions * @since 2.0.0 */ export var fromOptions = function (fe, fa) { return _.isNone(fe) ? _.isNone(fa) ? _.none : _.some(right(fa.value)) : _.isNone(fa) ? _.some(left(fe.value)) : _.some(both(fe.value, fa.value)); }; var _map = function (fa, f) { return pipe(fa, map(f)); }; /* istanbul ignore next */ var _bimap = function (fa, f, g) { return pipe(fa, bimap(f, g)); }; /* istanbul ignore next */ var _mapLeft = function (fa, f) { return pipe(fa, mapLeft(f)); }; /* istanbul ignore next */ var _reduce = function (fa, b, f) { return pipe(fa, reduce(b, f)); }; /* istanbul ignore next */ var _foldMap = function (M) { var foldMapM = foldMap(M); return function (fa, f) { return pipe(fa, foldMapM(f)); }; }; /* istanbul ignore next */ var _reduceRight = function (fa, b, f) { return pipe(fa, reduceRight(b, f)); }; /* istanbul ignore next */ var _traverse = function (F) { var traverseF = traverse(F); return function (ta, f) { return pipe(ta, traverseF(f)); }; }; /** * Map a pair of functions over the two type arguments of the bifunctor. * * @category mapping * @since 2.0.0 */ export var bimap = function (f, g) { return function (fa) { return isLeft(fa) ? left(f(fa.left)) : isRight(fa) ? right(g(fa.right)) : both(f(fa.left), g(fa.right)); }; }; /** * Map a function over the first type argument of a bifunctor. * * @category error handling * @since 2.0.0 */ export var mapLeft = function (f) { return function (fa) { return isLeft(fa) ? left(f(fa.left)) : isBoth(fa) ? both(f(fa.left), fa.right) : fa; }; }; /** * `map` can be used to turn functions `(a: A) => B` into functions `(fa: F) => F` whose argument and return types * use the type constructor `F` to represent some computational context. * * @category mapping * @since 2.0.0 */ export var map = function (f) { return function (fa) { return isLeft(fa) ? fa : isRight(fa) ? right(f(fa.right)) : both(fa.left, f(fa.right)); }; }; /** * @category folding * @since 2.0.0 */ export var reduce = function (b, f) { return function (fa) { return isLeft(fa) ? b : f(b, fa.right); }; }; /** * @category folding * @since 2.0.0 */ export var foldMap = function (M) { return function (f) { return function (fa) { return isLeft(fa) ? M.empty : f(fa.right); }; }; }; /** * @category folding * @since 2.0.0 */ export var reduceRight = function (b, f) { return function (fa) { return isLeft(fa) ? b : f(fa.right, b); }; }; /** * @category traversing * @since 2.6.3 */ export var traverse = function (F) { return function (f) { return function (ta) { return isLeft(ta) ? F.of(ta) : isRight(ta) ? F.map(f(ta.right), right) : F.map(f(ta.right), function (b) { return both(ta.left, b); }); }; }; }; /** * @category traversing * @since 2.6.3 */ export var sequence = function (F) { return function (ta) { return isLeft(ta) ? F.of(ta) : isRight(ta) ? F.map(ta.right, right) : F.map(ta.right, function (b) { return both(ta.left, b); }); }; }; /** * @category constructors * @since 2.0.0 */ export var of = right; /** * @category type lambdas * @since 2.0.0 */ export var URI = 'These'; /** * @category instances * @since 2.7.0 */ export var Functor = { URI: URI, map: _map }; /** * @category mapping * @since 2.10.0 */ export var flap = /*#__PURE__*/ flap_(Functor); /** * @category instances * @since 2.10.0 */ export var Pointed = { URI: URI, of: of }; /** * @category instances * @since 2.7.0 */ export var Bifunctor = { URI: URI, bimap: _bimap, mapLeft: _mapLeft }; /** * @category instances * @since 2.11.0 */ export var FromThese = { URI: URI, fromThese: identity }; /** * @category instances * @since 2.7.0 */ export var Foldable = { URI: URI, reduce: _reduce, foldMap: _foldMap, reduceRight: _reduceRight }; /** * @category instances * @since 2.7.0 */ export var Traversable = { URI: URI, map: _map, reduce: _reduce, foldMap: _foldMap, reduceRight: _reduceRight, traverse: _traverse, sequence: sequence }; /** * @category instances * @since 2.10.0 */ export var FromEither = { URI: URI, fromEither: identity }; /** * @category lifting * @since 2.13.0 */ export var fromPredicate = /*#__PURE__*/ fromPredicate_(FromEither); /** * @category conversions * @since 2.10.0 */ export var fromOption = /*#__PURE__*/ fromOption_(FromEither); /** * @category lifting * @since 2.10.0 */ export var fromOptionK = /*#__PURE__*/ fromOptionK_(FromEither); // ------------------------------------------------------------------------------------- // utils // ------------------------------------------------------------------------------------- /** * @since 2.11.0 */ export var elem = function (E) { return function (a) { return function (ma) { return isLeft(ma) ? false : E.equals(a, ma.right); }; }; }; /** * @since 2.11.0 */ export var exists = function (predicate) { return function (ma) { return isLeft(ma) ? false : predicate(ma.right); }; }; /** * @example * import { toTuple2, left, right, both } from 'fp-ts/These' * * assert.deepStrictEqual(toTuple2(() => 'a', () => 1)(left('b')), ['b', 1]) * assert.deepStrictEqual(toTuple2(() => 'a', () => 1)(right(2)), ['a', 2]) * assert.deepStrictEqual(toTuple2(() => 'a', () => 1)(both('b', 2)), ['b', 2]) * * @category conversions * @since 2.10.0 */ export var toTuple2 = function (e, a) { return function (fa) { return isLeft(fa) ? [fa.left, a()] : isRight(fa) ? [e(), fa.right] : [fa.left, fa.right]; }; }; // ------------------------------------------------------------------------------------- // deprecated // ------------------------------------------------------------------------------------- /** * Use [`toTuple2`](#totuple2) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ export var toTuple = function (e, a) { return toTuple2(function () { return e; }, function () { return a; }); }; /** * @since 2.11.0 */ export var ApT = /*#__PURE__*/ of(_.emptyReadonlyArray); // ------------------------------------------------------------------------------------- // array utils // ------------------------------------------------------------------------------------- /** * Equivalent to `ReadonlyNonEmptyArray#traverseWithIndex(getApplicative(S))`. * * @category traversing * @since 2.11.0 */ export var traverseReadonlyNonEmptyArrayWithIndex = function (S) { return function (f) { return function (as) { var e = _.none; var t = f(0, _.head(as)); if (isLeft(t)) { return t; } if (isBoth(t)) { e = _.some(t.left); } var out = [t.right]; for (var i = 1; i < as.length; i++) { var t_1 = f(i, as[i]); if (isLeft(t_1)) { return t_1; } if (isBoth(t_1)) { e = _.isNone(e) ? _.some(t_1.left) : _.some(S.concat(e.value, t_1.left)); } out.push(t_1.right); } return _.isNone(e) ? right(out) : both(e.value, out); }; }; }; /** * Equivalent to `ReadonlyArray#traverseWithIndex(getApplicative(S))`. * * @category traversing * @since 2.11.0 */ export var traverseReadonlyArrayWithIndex = function (S) { return function (f) { var g = traverseReadonlyNonEmptyArrayWithIndex(S)(f); return function (as) { return (_.isNonEmpty(as) ? g(as) : ApT); }; }; }; // ------------------------------------------------------------------------------------- // deprecated // ------------------------------------------------------------------------------------- /** * This instance is deprecated, use small, specific instances instead. * For example if a function needs a `Functor` instance, pass `T.Functor` instead of `T.these` * (where `T` is from `import T from 'fp-ts/These'`) * * @category zone of death * @since 2.0.0 * @deprecated */ export var these = { URI: URI, map: _map, bimap: _bimap, mapLeft: _mapLeft, reduce: _reduce, foldMap: _foldMap, reduceRight: _reduceRight, traverse: _traverse, sequence: sequence };