@jsoldi/hkt
Version:
Higher kinded types for typescript and a few utility monads.
95 lines • 3.05 kB
JavaScript
import { pipe } from "../core/utils.js";
import { monad } from "../classes/monad.js";
import { monadTrans } from "../classes/transformer.js";
/** The either module with no fixed left type. */
const core = {
of: () => eitherOf(),
right: (b) => ({ right: true, value: b }),
left: (a) => ({ right: false, value: a }),
either: (onLeft, onRight) => (fa) => fa.right ? onRight(fa.value) : onLeft(fa.value),
bimap: (onLeft, onRight) => (fa) => fa.right ? core.right(onRight(fa.value)) : core.left(onLeft(fa.value)),
lefts: (fa) => {
const result = [];
for (const a of fa) {
if (!a.right)
result.push(a.value);
}
return result;
},
rights: (fa) => {
const result = [];
for (const a of fa) {
if (a.right)
result.push(a.value);
}
return result;
},
or: b => fa => fa.right ? fa : b,
and: b => fa => fa.right ? b : fa,
else: b => fa => fa.right ? fa.value : b(),
isLeft: (fa) => !fa.right,
isRight: (fa) => fa.right,
fromLeft: (a) => (fa) => fa.right ? a : fa.value,
fromRight: (b) => (fa) => fa.right ? fa.value : b,
partition: (fa) => {
const result = { lefts: [], rights: [] };
for (const a of fa) {
if (a.right)
result.rights.push(a.value);
else
result.lefts.push(a.value);
}
return result;
},
try: (onTry, onCatch) => {
try {
return core.right(onTry());
}
catch (e) {
return core.left(onCatch?.(e) ?? e);
}
},
tryAsync: async (onTry, onCatch) => {
try {
return core.right(await onTry());
}
catch (e) {
return core.left(await onCatch?.(e) ?? e);
}
},
throwLeft: (fa) => {
if (!fa.right)
throw fa.value;
return fa.value;
},
throwRight: (fa) => {
if (fa.right)
throw fa.value;
return fa.value;
}
};
/** Creates an `IEither` with a fixed left type. */
function eitherOf() {
return pipe(core, base => ({
...monad({
unit: base.right,
bind: (fa, f) => fa.right ? f(fa.value) : fa,
}),
...base
}), base => ({
append: (fa, fb) => fa.right ? fa : fb,
transform: (outer) => {
return monadTrans({
map: (fa, f) => outer.map(fa, a => base.map(a, f)),
unit: (a) => outer.unit(base.right(a)),
bind: (fa, f) => outer.bind(fa, a => a.right ? f(a.value) : outer.unit(a)),
lift: (a) => outer.map(a, base.right),
wrap: a => outer.unit(a),
});
},
...base
}));
}
/** The `either` module, providing a set of functions for working with `Either` values. The left type is fixed to `any`. To change the left type, call the `of` function. */
export const either = eitherOf();
//# sourceMappingURL=either.js.map