From d424e8cfbf28c4d429ccf5789343831c4db109cc Mon Sep 17 00:00:00 2001 From: Brandon Blaylock Date: Thu, 5 Oct 2023 10:39:47 -0700 Subject: [PATCH] feat: readied applicable, array, renamed reducible --- .fslckout | Bin 0 -> 57344 bytes applicable.ts | 85 +++++++++++++++++++++++++++-- array.ts | 45 ++++++++++++---- async.ts | 94 +++++++++++++++++++++++++++++++++ async_either.ts | 25 ++++++++- async_iterable.ts | 10 ++-- combinable.ts | 2 +- datum.ts | 4 +- decoder.ts | 6 +-- either.ts | 8 +-- examples/hkts.ts | 28 ++++++---- flake.lock | 12 ++--- flake.nix | 2 +- foldable.ts | 38 +++++++++++++ free.ts | 6 +-- initializable.ts | 2 +- iterable.ts | 10 ++-- map.ts | 10 ++-- mod.ts | 2 +- optic.ts | 4 +- option.ts | 22 ++++---- pair.ts | 18 +++---- record.ts | 30 +++++------ set.ts | 18 +++---- sync.ts | 8 +-- sync_either.ts | 6 +-- testing/applicable.test.ts | 40 ++++++++++++++ testing/array.test.ts | 37 +++++++++++-- testing/async.test.ts | 70 +++++++++++++++++------- testing/async_iterable.test.ts | 4 +- testing/datum.test.ts | 12 ++--- testing/decoder.test.ts | 6 +-- testing/either.test.ts | 8 +-- testing/foldable.test.ts | 11 ++++ testing/free.test.ts | 4 +- testing/iterable.test.ts | 4 +- testing/map.test.ts | 6 +-- testing/option.test.ts | 8 +-- testing/pair.test.ts | 10 ++-- testing/record.test.ts | 16 +++--- testing/set.test.ts | 10 ++-- testing/sync.test.ts | 6 +-- testing/sync_either.test.ts | 8 +-- testing/these.test.ts | 10 ++-- testing/tree.test.ts | 8 +-- these.ts | 8 +-- traversable.ts | 10 ++-- tree.ts | 10 ++-- 48 files changed, 592 insertions(+), 209 deletions(-) create mode 100644 .fslckout create mode 100644 foldable.ts create mode 100644 testing/foldable.test.ts diff --git a/.fslckout b/.fslckout new file mode 100644 index 0000000000000000000000000000000000000000..181ea9d356e9ff1032e80f27870d4a59c90886f6 GIT binary patch literal 57344 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 ) => Combinable<$> { return ( { combine }: Combinable, - ): Combinable<$> => ({ - combine: (second) => (first) => apply(first)(map(combine)(second)), - }); + ): Combinable<$> => { + const _map = map(combine); + return { + combine: (second) => (first) => apply(first)(_map(second)), + }; + }; +} + +/** + * Compose two Applicables into a new apply function. + * + * @since 2.0.0 + */ +export function apply( + U: Applicable, + V: Applicable, +): < + A, + B = never, + C = never, + D = unknown, + E = unknown, + J = never, + K = never, + L = unknown, + M = unknown, +>( + uva: $, J, K], [L], [M]>, +) => ( + uvfai: $ I, B, C], [D], [E]>, J, K], [L], [M]>, +) => $, J, K], [L], [M]> { + return < + A, + B = never, + C = never, + D = unknown, + E = unknown, + J = never, + K = never, + L = unknown, + M = unknown, + >(uva: $, J, K], [L], [M]>) => + ( + uvfai: $ I, B, C], [D], [E]>, J, K], [L], [M]>, + ): $, J, K], [L], [M]> => { + return U.apply(uva)( + U.map( + (vfai: $ I, B, C], [D], [E]>) => + (va: $) => V.apply(va)(vfai), + )(uvfai), + ); + }; +} + +/** + * @since 2.0.0 + */ +export function applyFirst( + U: Applicable, +): ( + second: $, +) => (first: $) => $ { + return ( + second: $, + ) => + (first: $): $ => + U.apply(second)(U.map((a: A) => (_: I) => a)(first)); +} + +/** + * @since 2.0.0 + */ +export function applySecond( + U: Applicable, +): ( + second: $, +) => (first: $) => $ { + return ( + second: $, + ) => + (first: $): $ => + U.apply(second)(U.map(() => (i: I) => i)(first)); } diff --git a/array.ts b/array.ts index 0a7e6e3..77b37f0 100644 --- a/array.ts +++ b/array.ts @@ -9,6 +9,7 @@ import type { $, AnySub, Intersect, Kind, Out } from "./kind.ts"; import type { Applicable } from "./applicable.ts"; +import type { Combinable } from "./combinable.ts"; import type { Comparable } from "./comparable.ts"; import type { Either } from "./either.ts"; import type { Filterable } from "./filterable.ts"; @@ -17,12 +18,14 @@ import type { Initializable } from "./initializable.ts"; import type { Mappable } from "./mappable.ts"; import type { Option } from "./option.ts"; import type { Pair } from "./pair.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Showable } from "./showable.ts"; import type { Sortable } from "./sortable.ts"; import type { Traversable } from "./traversable.ts"; import type { Wrappable } from "./wrappable.ts"; +import { createBind, createTap } from "./flatmappable.ts"; +import { createBindTo } from "./mappable.ts"; import { pair } from "./pair.ts"; import { isRight } from "./either.ts"; import { fromCompare } from "./comparable.ts"; @@ -30,9 +33,6 @@ import { fromSort, sign } from "./sortable.ts"; import { isSome, none, some } from "./option.ts"; import { identity, pipe } from "./fn.ts"; -const NameReadonlyArray = "ReadonlyArray"; -type NameReadonlyArray = typeof NameReadonlyArray; - /** * This type can be used as a placeholder for an array of any type. * @@ -71,7 +71,6 @@ export type AnyNonEmptyArray = NonEmptyArray; * @since 2.0.0 */ export interface KindArray extends Kind { - readonly name: NameReadonlyArray; readonly kind: ReadonlyArray>; } @@ -412,7 +411,7 @@ export function map( * * const result = pipe( * A.range(5, 1), - * A.reduce((sum, value, index) => sum + value + index, 0), + * A.fold((sum, value, index) => sum + value + index, 0), * ); * // 0 + 0 + 0 = 0 * // 0 + 1 + 1 = 2 @@ -424,7 +423,7 @@ export function map( * * @since 2.0.0 */ -export function reduce( +export function fold( foao: (o: O, a: A, i: number) => O, o: O, ): (ua: ReadonlyArray) => O { @@ -803,7 +802,7 @@ export function traverse( favi: (a: A, i: number) => $, ): (ua: ReadonlyArray) => $, J, K], [L], [M]> => { const pusher = (is: I[]) => (i: I) => [...is, i]; - return reduce( + return fold( (vis, a: A, index) => pipe( vis, @@ -1129,7 +1128,7 @@ export function deleteAt(index: number) { * sort(ordNumber)([3, 1, 2]) * // [1, 2, 3] * - * @category combinators + * @since 2.0.0 */ export function sort( O: Sortable, @@ -1283,6 +1282,15 @@ export function zip>( } } +/** + * @since 2.0.0 + */ +export function getCombinableArray(): Combinable> { + return { + combine, + }; +} + /** * Given an instance Comparable create a Comparable>. * @@ -1434,14 +1442,14 @@ export const MappableArray: Mappable = { map }; /** * @since 2.0.0 */ -export const ReducibleArray: Reducible = { reduce }; +export const FoldableArray: Foldable = { fold }; /** * @since 2.0.0 */ export const TraversableArray: Traversable = { map, - reduce, + fold, traverse, }; @@ -1449,3 +1457,18 @@ export const TraversableArray: Traversable = { * @since 2.0.0 */ export const WrappableArray: Wrappable = { wrap }; + +/** + * @since 2.0.0 + */ +export const tap = createTap(FlatmappableArray); + +/** + * @since 2.0.0 + */ +export const bind = createBind(FlatmappableArray); + +/** + * @since 2.0.0 + */ +export const bindTo = createBindTo(MappableArray); diff --git a/async.ts b/async.ts index cfcb6a8..e219d93 100644 --- a/async.ts +++ b/async.ts @@ -1,27 +1,55 @@ +/** + * This file contains the Async algebraic data type. Async is a lazy, + * asynchronous adt that is useful for encapsulating anything from file reads + * and network requests to timers and loops. + * + * @module Async + * @since 2.0.0 + */ + import type { Kind, Out } from "./kind.ts"; import type { Applicable } from "./applicable.ts"; +import type { Combinable } from "./combinable.ts"; +import type { Initializable } from "./initializable.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Mappable } from "./mappable.ts"; import type { Sync } from "./sync.ts"; import type { Wrappable } from "./wrappable.ts"; +import { createBindTo } from "./mappable.ts"; +import { createBind, createTap } from "./flatmappable.ts"; import { resolve, wait } from "./promise.ts"; import { handleThrow } from "./fn.ts"; +/** + * @since 2.0.0 + */ export type Async = Sync>; +/** + * @since 2.0.0 + */ export interface KindAsync extends Kind { readonly kind: Async>; } +/** + * @since 2.0.0 + */ export function delay(ms: number): (ma: Async) => Async { return (ta) => () => wait(ms).then(ta); } +/** + * @since 2.0.0 + */ export function fromSync(fa: Sync): Async { return () => resolve(fa()); } +/** + * @since 2.0.0 + */ export function tryCatch( fasr: (...as: AS) => A | PromiseLike, onThrow: (e: unknown, as: AS) => A, @@ -36,41 +64,107 @@ export function tryCatch( }; } +/** + * @since 2.0.0 + */ export function wrap(a: A): Async { return () => resolve(a); } +/** + * @since 2.0.0 + */ export function map(fai: (a: A) => I): (ta: Async) => Async { return (ta) => () => ta().then(fai); } +/** + * @since 2.0.0 + */ export function apply( ua: Async, ): (ufai: Async<(a: A) => I>) => Async { return (ufai) => () => Promise.all([ufai(), ua()]).then(([fai, a]) => fai(a)); } +/** + * @since 2.0.0 + */ export function applySequential( ua: Async, ): (ufai: Async<(a: A) => I>) => Async { return (ufai) => async () => (await ufai())(await ua()); } +/** + * @since 2.0.0 + */ export function flatmap( fati: (a: A) => Async, ): (ta: Async) => Async { return (ta) => () => ta().then((a) => fati(a)()); } +/** + * @since 2.0.0 + */ +export function getCombinableAsync( + { combine }: Combinable, +): Combinable> { + return { + combine: (second) => (first) => async () => + combine(await second())(await first()), + }; +} + +/** + * @since 2.0.0 + */ +export function getInitializableAsync( + I: Initializable, +): Initializable> { + return { + init: () => async () => await I.init(), + ...getCombinableAsync(I), + }; +} + +/** + * @since 2.0.0 + */ export const WrappableAsync: Wrappable = { wrap }; +/** + * @since 2.0.0 + */ export const ApplicableAsync: Applicable = { apply, map, wrap }; +/** + * @since 2.0.0 + */ export const MappableAsync: Mappable = { map }; +/** + * @since 2.0.0 + */ export const FlatmappableAsync: Flatmappable = { apply, flatmap, map, wrap, }; + +/** + * @since 2.0.0 + */ +export const tap = createTap(FlatmappableAsync); + +/** + * @since 2.0.0 + */ +export const bind = createBind(FlatmappableAsync); + +/** + * @since 2.0.0 + */ +export const bindTo = createBindTo(MappableAsync); diff --git a/async_either.ts b/async_either.ts index acb76e3..770bc98 100644 --- a/async_either.ts +++ b/async_either.ts @@ -5,11 +5,13 @@ * safety. * * @module AsyncEither - * * @since 2.0.0 */ + import type { Kind, Out } from "./kind.ts"; +import type { Applicable } from "./applicable.ts"; import type { Bimappable } from "./bimappable.ts"; +import type { Combinable } from "./combinable.ts"; import type { Either } from "./either.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Async } from "./async.ts"; @@ -364,6 +366,27 @@ export function match( // (ta: AsyncEither): AsyncEither => // () => Promise.race([ta(), wait(ms).then(flow(onTimeout, E.left))]); +/** + * @since 2.0.0 + */ +export function getCombinableAsyncEither(CA: Combinable, CB: Combinable): Combinable> { + const combinableEither = E.getRightInitializable + + return { + combine: second => first => async () => + + } +} + +/** + * @since 2.0.0 + */ +export const ApplicableAsyncEither: Applicable = { + apply, + map, + wrap, +}; + /** * @since 2.0.0 */ diff --git a/async_iterable.ts b/async_iterable.ts index 0a59045..fa93f77 100644 --- a/async_iterable.ts +++ b/async_iterable.ts @@ -222,15 +222,15 @@ export function partitionMap( }; } -export function reduce( - reducer: (value: O, accumulator: A, index: number) => O, +export function fold( + foldr: (value: O, accumulator: A, index: number) => O, initial: O, ): (ta: AsyncIterable) => Promise { return async (ta) => { let index = 0; let result = initial; for await (const value of ta) { - result = reducer(result, value, index++); + result = foldr(result, value, index++); } return result; }; @@ -267,7 +267,7 @@ export function takeWhile( } export function scan( - reducer: (accumulator: O, value: A, index: number) => O, + foldr: (accumulator: O, value: A, index: number) => O, initial: O, ): (ta: AsyncIterable) => AsyncIterable { return (ta) => @@ -275,7 +275,7 @@ export function scan( let result = initial; let index = 0; for await (const a of ta) { - result = reducer(result, a, index++); + result = foldr(result, a, index++); yield result; } }); diff --git a/combinable.ts b/combinable.ts index 72368e9..a2c83a2 100644 --- a/combinable.ts +++ b/combinable.ts @@ -364,7 +364,7 @@ export function constant(a: A): Combinable { /** * Given a Combinable, create a function that will * iterate through an array of values and combine - * them. This is not much more than Array.reduce(combine). + * them. This is not much more than Array.fold(combine). * * @example * ```ts diff --git a/datum.ts b/datum.ts index caf3ff5..156e1fa 100644 --- a/datum.ts +++ b/datum.ts @@ -191,7 +191,7 @@ export function alt(tb: Datum): (ta: Datum) => Datum { return (ta) => isSome(ta) ? ta : tb; } -export function reduce( +export function fold( foao: (o: O, a: A) => O, o: O, ): (ta: Datum) => O { @@ -279,6 +279,6 @@ export const FlatmappableDatum: Flatmappable = { export const TraversableDatum: Traversable = { map, - reduce, + fold, traverse, }; diff --git a/decoder.ts b/decoder.ts index 86e2308..7f2ca9a 100644 --- a/decoder.ts +++ b/decoder.ts @@ -474,9 +474,9 @@ export function manyErr( * (_, err) => countErrors(err), * (_, __, err) => countErrors(err), * (_, __, err) => countErrors(err), - * A.reduce((acc, err) => acc + countErrors(err), 0), - * A.reduce((acc, err) => acc + countErrors(err), 0), - * A.reduce((acc, err) => acc + countErrors(err), 0), + * A.fold((acc, err) => acc + countErrors(err), 0), + * A.fold((acc, err) => acc + countErrors(err), 0), + * A.fold((acc, err) => acc + countErrors(err), 0), * ); * * const result1 = countErrors(D.leafErr(1, "expected string")); // 1 diff --git a/either.ts b/either.ts index eb7afb3..b7bc153 100644 --- a/either.ts +++ b/either.ts @@ -8,7 +8,7 @@ import type { Failable } from "./failable.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Mappable } from "./mappable.ts"; import type { Predicate } from "./predicate.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Refinement } from "./refinement.ts"; import type { Showable } from "./showable.ts"; import type { Sortable } from "./sortable.ts"; @@ -274,7 +274,7 @@ export function alt( return (ta) => isLeft(ta) ? tb : ta; } -export function reduce( +export function fold( foao: (o: O, a: A) => O, o: O, ): (ta: Either) => O { @@ -316,11 +316,11 @@ export const FlatmappableEither: Flatmappable = { export const MappableEither: Mappable = { map }; -export const ReducibleEither: Reducible = { reduce }; +export const FoldableEither: Foldable = { fold }; export const TraversableEither: Traversable = { map, - reduce, + fold, traverse, }; diff --git a/examples/hkts.ts b/examples/hkts.ts index adfa3ba..969bf95 100644 --- a/examples/hkts.ts +++ b/examples/hkts.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-explicit-any ban-types -import { pipe } from "../fns.ts"; +import { pipe } from "../fn.ts"; /** * This is here just to show a different path for @@ -51,23 +51,22 @@ export type Primitives = export type $ = T extends Fix ? F : T extends _ ? S[N] - : T extends Primitives ? T : T extends any[] ? { [K in keyof T]: $ } : T extends (...as: infer AS) => infer R ? (...as: $) => $ : T extends Promise ? Promise<$> : T extends object ? { [K in keyof T]: $ } - : T extends unknown ? never - : T; + : T extends Primitives ? T + : never; // --- // Type Classes // --- -export type FunctorFn = ( +export type FunctorFn = ( fai: (a: A) => I, -) => (ta: $) => $; +) => (ta: $) => $; -export type ApplyFn = ( +export type ApplyFn = ( tfai: $ I]>, ) => (ta: $) => $; @@ -131,14 +130,25 @@ export const traversePromise = traverse(ApplicativePromise); export type Left = { tag: "Left"; left: B }; export type Right = { tag: "Right"; right: A }; -export type Either = Left | Right; +export type Either = Left | Right; export const left = (left: B): Either => ({ tag: "Left", left }); export const right = (right: A): Either => ({ tag: "Right", right, }); -export const ApplicativeEither: Applicative> = { +export const mapEither: FunctorFn> = (fai) => (ua) => + ua.tag === "Right" ? right(fai(ua.right)) : ua; +export const mapEitherT1 = pipe( + right(1), + mapEither((n) => n + 1), +); +export const mapEitherT2 = pipe( + left(1), + mapEither((n: number) => n + 1), +); + +export const ApplicativeEither: Applicative> = { of: right, ap: (tfai: Either I>) => (ta: Either) => ta.tag === "Left" diff --git a/flake.lock b/flake.lock index c4c91c8..dcb737d 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1692799911, - "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", "owner": "numtide", "repo": "flake-utils", - "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1693844670, - "narHash": "sha256-t69F2nBB8DNQUWHD809oJZJVE+23XBrth4QZuVd6IE0=", + "lastModified": 1696419054, + "narHash": "sha256-EdR+dIKCfqL3voZUDYwcvgRDOektQB9KbhBVcE0/3Mo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "3c15feef7770eb5500a4b8792623e2d6f598c9c1", + "rev": "7131f3c223a2d799568e4b278380cd9dac2b8579", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 796a1aa..5b9ba3f 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,7 @@ }; shell = with pkgs; mkShell { - buildInputs = [ deno nodejs jq lcov ]; + buildInputs = [ deno nodejs jq lcov jujutsu ]; }; in diff --git a/foldable.ts b/foldable.ts new file mode 100644 index 0000000..b4d73a8 --- /dev/null +++ b/foldable.ts @@ -0,0 +1,38 @@ +/** + * Foldable is a structure that allows a function to all values inside of a + * structure. The reduction is accumulative and ordered. + * + * @module Foldable + * @since 2.0.0 + */ + +import type { $, Hold, Kind } from "./kind.ts"; +import type { Initializable } from "./initializable.ts"; + +/** + * A Foldable structure has the method fold. + * + * @since 2.0.0 + */ +export interface Foldable extends Hold { + readonly fold: ( + reducer: (accumulator: O, value: A) => O, + accumulator: O, + ) => ( + ua: $, + ) => O; +} + +/** + * @experimental + * @since 2.0.0 + */ +export function collect( + { fold }: Foldable, + { combine, init }: Initializable, +): ( + ua: $, +) => A { + return (ua) => + fold((first, second) => combine(second)(first), init())(ua); +} diff --git a/free.ts b/free.ts index ed4e552..6a116fc 100644 --- a/free.ts +++ b/free.ts @@ -89,15 +89,15 @@ export function apply(ua: Free): (ufai: Free<(a: A) => I>) => Free { return (ufai) => pipe(ufai, flatmap(flow(map, (fn) => fn(ua)))); } -export function reduce( - reducer: (value: A, accumulator: O) => O, +export function fold( + foldr: (value: A, accumulator: O) => O, initial: O, ): (ua: Free) => O { // :( let result = initial; const go: (ua: Free) => O = match( (value) => { - result = reducer(value, result); + result = foldr(value, result); return result; }, (first, second) => { diff --git a/initializable.ts b/initializable.ts index 3f7a9c7..366db4f 100644 --- a/initializable.ts +++ b/initializable.ts @@ -148,7 +148,7 @@ export function intercalcate(middle: A) { /** * Given an Initializable, create a function that will * iterate through an array of values and combine - * them. This is not much more than Array.reduce(combine). + * them. This is not much more than Array.fold(combine). * * @example * ```ts diff --git a/iterable.ts b/iterable.ts index 4d3a267..850f477 100644 --- a/iterable.ts +++ b/iterable.ts @@ -143,14 +143,14 @@ export function forEach(fa: (a: A) => void): (ta: Iterable) => void { /** * @since 2.0.0 */ -export function reduce( - reducer: (accumulator: O, value: A) => O, +export function fold( + foldr: (accumulator: O, value: A) => O, initial: O, ) { return (ua: Iterable): O => { let out = initial; for (const a of ua) { - out = reducer(out, a); + out = foldr(out, a); } return out; }; @@ -160,7 +160,7 @@ export function reduce( * @since 2.0.0 */ export function scan( - reducer: (accumulator: O, value: A, index: number) => O, + foldr: (accumulator: O, value: A, index: number) => O, initial: O, ): (ta: Iterable) => Iterable { return (ta) => @@ -168,7 +168,7 @@ export function scan( let result = initial; let index = 0; for (const a of ta) { - result = reducer(result, a, index++); + result = foldr(result, a, index++); yield result; } }); diff --git a/map.ts b/map.ts index 3fd6c70..f82f56b 100644 --- a/map.ts +++ b/map.ts @@ -4,7 +4,7 @@ import type { Combinable } from "./combinable.ts"; import type { Comparable } from "./comparable.ts"; import type { Mappable } from "./mappable.ts"; import type { Option } from "./option.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Showable } from "./showable.ts"; import type { Sortable } from "./sortable.ts"; @@ -144,14 +144,14 @@ export function values(O: Sortable): (ta: ReadonlyMap) => A[] { return (ta) => Array.from(ta.values()).sort(O.sort); } -export function reduce( - reducer: (accumulator: O, value: A, key: B) => O, +export function fold( + foldr: (accumulator: O, value: A, key: B) => O, initial: O, ) { return (ua: ReadonlyMap): O => { let result = initial; for (const [key, value] of ua.entries()) { - result = reducer(result, value, key); + result = foldr(result, value, key); } return result; }; @@ -306,7 +306,7 @@ export const MappableMap: Mappable = { map }; export const BimappableMap: Bimappable = { map, mapSecond }; -export const ReducibleMap: Reducible = { reduce }; +export const FoldableMap: Foldable = { fold }; export function getShowable( SK: Showable, diff --git a/mod.ts b/mod.ts index fb0923c..0bfa71f 100644 --- a/mod.ts +++ b/mod.ts @@ -32,7 +32,7 @@ export * as pair from "./pair.ts"; export * as predicate from "./predicate.ts"; export * as premappable from "./premappable.ts"; export * as promise from "./promise.ts"; -export * as reducible from "./reducible.ts"; +export * as foldable from "./foldable.ts"; export * as refinement from "./refinement.ts"; export * as schemable from "./schemable.ts"; export * as set from "./set.ts"; diff --git a/optic.ts b/optic.ts index e9487f5..5ee7723 100644 --- a/optic.ts +++ b/optic.ts @@ -1272,7 +1272,7 @@ export function atMap(eq: Comparable): (key: B) => ( /** * Construct a composable optic from a Traversable instance for a Kind T. This - * will reduce the values wrapped in the Kind T into a single Array when viewed. + * will fold the values wrapped in the Kind T into a single Array when viewed. * * @example * ```ts @@ -1305,7 +1305,7 @@ export function traverse( first: Optic>, ) => Optic, S, A> { return compose(fold( - T.reduce((as, a) => [...as, a], A.init()), + T.fold((as, a) => [...as, a], A.init()), T.map, )); } diff --git a/option.ts b/option.ts index e4b2ca4..73a9161 100644 --- a/option.ts +++ b/option.ts @@ -17,7 +17,7 @@ import type { Initializable } from "./initializable.ts"; import type { Mappable } from "./mappable.ts"; import type { Pair } from "./pair.ts"; import type { Predicate } from "./predicate.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Refinement } from "./refinement.ts"; import type { Showable } from "./showable.ts"; import type { Sortable } from "./sortable.ts"; @@ -615,26 +615,26 @@ export function partitionMap( /** * Reduce over an Option. Since an Option contains at most one value this * function operates a lot like getOrElse. If the passed option is None then it - * returns the initial value, otherwise the reducer function is called with both + * returns the initial value, otherwise the foldr function is called with both * the initial value and the inner A. * * @example * ```ts * import * as O from "./option.ts"; * - * const reduce = O.reduce((n: number, m: number) => n + m, 0); + * const fold = O.fold((n: number, m: number) => n + m, 0); * - * const result1 = reduce(O.some(1)); // 1 - * const result2 = reduce(O.none); // 0 + * const result1 = fold(O.some(1)); // 1 + * const result2 = fold(O.none); // 0 * ``` * * @since 2.0.0 */ -export function reduce( - reducer: (accumulator: O, current: A) => O, +export function fold( + foldr: (accumulator: O, current: A) => O, initial: O, ): (ua: Option) => O { - return (ua) => isSome(ua) ? reducer(initial, ua.value) : initial; + return (ua) => isSome(ua) ? foldr(initial, ua.value) : initial; } /** @@ -697,11 +697,11 @@ export const FilterableOption: Filterable = { }; /** - * The canonical implementation of Reducible for Option. + * The canonical implementation of Foldable for Option. * * @since 2.0.0 */ -export const ReducibleOption: Reducible = { reduce }; +export const FoldableOption: Foldable = { fold }; /** * The canonical implementation of Traversable for Option. @@ -710,7 +710,7 @@ export const ReducibleOption: Reducible = { reduce }; */ export const TraversableOption: Traversable = { map, - reduce, + fold, traverse, }; diff --git a/pair.ts b/pair.ts index 90f8fd2..a1bf662 100644 --- a/pair.ts +++ b/pair.ts @@ -12,7 +12,7 @@ import type { Bimappable } from "./bimappable.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Initializable } from "./initializable.ts"; import type { Mappable } from "./mappable.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Showable } from "./showable.ts"; import type { Traversable } from "./traversable.ts"; @@ -328,22 +328,22 @@ export function unwrap([first]: Pair): A { /** * Reduces a pair with an initial value, also passing - * the second value into the reducer as well. + * the second value into the foldr as well. * * @example * ```ts - * import { pair, reduce } from "./pair.ts"; + * import { pair, fold } from "./pair.ts"; * import { pipe } from "./fn.ts"; * * const result = pipe( * pair(10, 20), - * reduce(Math.max, Number.NEGATIVE_INFINITY), + * fold(Math.max, Number.NEGATIVE_INFINITY), * ); // 20 * ``` * * @since 2.0.0 */ -export function reduce( +export function fold( foao: (acc: O, first: A, second: B) => O, initial: O, ): (ua: Pair) => O { @@ -405,17 +405,17 @@ export const MappablePair: Mappable = { map }; export const BimappablePair: Bimappable = { mapSecond, map }; /** - * The canonical Reducible instance for Pair. Contains the - * reduce method. + * The canonical Foldable instance for Pair. Contains the + * fold method. * * @since 2.0.0 */ -export const ReduciblePair: Reducible = { reduce }; +export const FoldablePair: Foldable = { fold }; /** * @since 2.0.0 */ -export const TraversablePair: Traversable = { map, reduce, traverse }; +export const TraversablePair: Traversable = { map, fold, traverse }; /** * Creates a Showable instance for a pair, wrapping the Showable instances provided diff --git a/record.ts b/record.ts index 9a9de3b..2ce1f40 100644 --- a/record.ts +++ b/record.ts @@ -13,7 +13,7 @@ import type { Applicable } from "./applicable.ts"; import type { Either } from "./either.ts"; import type { Comparable } from "./comparable.ts"; import type { Filterable } from "./filterable.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Mappable } from "./mappable.ts"; import type { Initializable } from "./initializable.ts"; import type { Option } from "./option.ts"; @@ -217,13 +217,13 @@ export function map( * * const result = pipe( * { one: 1, two: 2 }, - * R.reduce((sum, value) => sum + value, 0), + * R.fold((sum, value) => sum + value, 0), * ); // 3 * ``` * * @since 2.0.0 */ -export function reduce( +export function fold( foao: (o: O, a: A, i: string) => O, o: O, ) { @@ -239,7 +239,7 @@ export function reduce( /** * Collect all values in a ReadonlyRecord into a single * value I by using a Combinable and a mapping function - * from A to I. This is effectively reduce using a Combinable + * from A to I. This is effectively fold using a Combinable * for the initial value. * * @example @@ -260,17 +260,17 @@ export function collect( M: Initializable, ): (fai: (a: A, index: string) => I) => (ua: ReadonlyRecord) => I { return (fai: (a: A, index: string) => I) => { - const reducer = reduce( + const foldr = fold( (i, a: A, index) => M.combine(fai(a, index))(i), M.init(), ); - return (ua: ReadonlyRecord) => reducer(ua); + return (ua: ReadonlyRecord) => foldr(ua); }; } /** * Collect all values in a ReadonlyRecord into a single - * value I by using a Combinable. This is effectively reduce + * value I by using a Combinable. This is effectively fold * using a Combinable for the initial value and combination. * * @example @@ -290,7 +290,7 @@ export function collect( export function collapse( M: Initializable, ): (ua: ReadonlyRecord) => A { - return reduce(uncurry2(M.combine), M.init()); + return fold(uncurry2(M.combine), M.init()); } /** @@ -338,7 +338,7 @@ export function traverse( i: I, ): Record => ({ ...is, [key]: i }); // Interior mutability is used to increase perf - const reducer = ( + const foldr = ( vis: $, J, K], [L], [M]>, a: A, key: string, @@ -349,7 +349,7 @@ export function traverse( A.apply(favi(a, key)), ); - return (ua) => pipe(ua, reduce(reducer, A.wrap({}))); + return (ua) => pipe(ua, fold(foldr, A.wrap({}))); }; } @@ -952,22 +952,22 @@ export const FilterableRecord: Filterable = { export const MappableRecord: Mappable = { map }; /** - * The canonical implementation of Reducible for ReadonlyRecord. It contains - * the method reduce. + * The canonical implementation of Foldable for ReadonlyRecord. It contains + * the method fold. * * @since 2.0.0 */ -export const ReducibleRecord: Reducible = { reduce }; +export const FoldableRecord: Foldable = { fold }; /** * The canonical implementation of Traversable for ReadonlyRecord. It contains - * the methods map, reduce, and traverse. + * the methods map, fold, and traverse. * * @since 2.0.0 */ export const TraversableRecord: Traversable = { map, - reduce, + fold, traverse, }; diff --git a/set.ts b/set.ts index 11d4766..f2ded73 100644 --- a/set.ts +++ b/set.ts @@ -10,7 +10,7 @@ import type { Applicable } from "./applicable.ts"; import type { Either } from "./either.ts"; import type { Comparable } from "./comparable.ts"; import type { Filterable } from "./filterable.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Mappable } from "./mappable.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Combinable } from "./combinable.ts"; @@ -677,13 +677,13 @@ export function partitionMap( * * const result = pipe( * set, - * S.reduce((previous, current) => previous + current, 0), + * S.fold((previous, current) => previous + current, 0), * ); // 10 * ``` * * @since 2.0.0 */ -export function reduce( +export function fold( foao: (o: O, a: A) => O, o: O, ): (ua: ReadonlySet) => O { @@ -736,7 +736,7 @@ export function traverse( return ( favi: (a: A) => $, ): (ua: ReadonlySet) => $, J, K], [L], [M]> => - reduce( + fold( (vis, a) => pipe(vis, A.map(unsafeAdd), A.apply(favi(a))), A.wrap(init() as Set), ); @@ -785,22 +785,22 @@ export const FilterableSet: Filterable = { }; /** - * The canonical implementation of Reducible for ReadonlySet. It contains - * the method reduce. + * The canonical implementation of Foldable for ReadonlySet. It contains + * the method fold. * * @since 2.0.0 */ -export const ReducibleSet: Reducible = { reduce }; +export const FoldableSet: Foldable = { fold }; /** * The canonical implementation of Traversable for ReadonlySet. It contains - * the methods map, reduce, and traverse. + * the methods map, fold, and traverse. * * @since 2.0.0 */ export const TraversableSet: Traversable = { map, - reduce, + fold, traverse, }; diff --git a/sync.ts b/sync.ts index 1ad20d5..2508b03 100644 --- a/sync.ts +++ b/sync.ts @@ -2,7 +2,7 @@ import type { $, Kind, Out } from "./kind.ts"; import type { Applicable } from "./applicable.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Mappable } from "./mappable.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Traversable } from "./traversable.ts"; import type { Wrappable } from "./wrappable.ts"; @@ -32,7 +32,7 @@ export function flatmap( return (ta) => flow(ta, fati, (x) => x()); } -export function reduce( +export function fold( foao: (o: O, a: A) => O, o: O, ): (ta: Sync) => O { @@ -60,6 +60,6 @@ export const FlatmappableSync: Flatmappable = { wrap, }; -export const ReducibleSync: Reducible = { reduce }; +export const FoldableSync: Foldable = { fold }; -export const TraversableSync: Traversable = { map, reduce, traverse }; +export const TraversableSync: Traversable = { map, fold, traverse }; diff --git a/sync_either.ts b/sync_either.ts index 7093ef7..4933654 100644 --- a/sync_either.ts +++ b/sync_either.ts @@ -3,7 +3,7 @@ import type { Bimappable } from "./bimappable.ts"; import type { Applicable } from "./applicable.ts"; import type { Mappable } from "./mappable.ts"; import type { Failable } from "./failable.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Sync } from "./sync.ts"; import type { Either } from "./either.ts"; @@ -97,7 +97,7 @@ export function alt( return (ta) => flow(ta, E.match(tb, E.right)); } -export function reduce( +export function fold( foao: (o: O, a: A) => O, o: O, ): (ta: SyncEither) => O { @@ -134,4 +134,4 @@ export const FailableSyncEither: Failable = { wrap, }; -export const ReducibleSyncEither: Reducible = { reduce }; +export const FoldableSyncEither: Foldable = { fold }; diff --git a/testing/applicable.test.ts b/testing/applicable.test.ts index d068570..1746dd2 100644 --- a/testing/applicable.test.ts +++ b/testing/applicable.test.ts @@ -17,3 +17,43 @@ Deno.test("Applicable getApplicableCombinable", () => { assertEquals(combineAll(O.some(1), O.none), O.none); assertEquals(combineAll(O.some(1), O.some(1)), O.some(2)); }); + +Deno.test("Applicable apply", () => { + const apply = A.apply(O.ApplicableOption, O.ApplicableOption); + const o1: O.Option> = O.none; + const o2: O.Option> = O.some(O.none); + const o3: O.Option> = O.some(O.some(1)); + const f1: O.Option [number, number]>> = O.none; + const f2: O.Option [number, number]>> = O.some( + O.none, + ); + const f3: O.Option [number, number]>> = O.some( + O.some((n) => [n, n + 1]), + ); + + assertEquals(apply(o1)(f1), O.none); + assertEquals(apply(o1)(f2), O.none); + assertEquals(apply(o1)(f3), O.none); + assertEquals(apply(o2)(f1), O.none); + assertEquals(apply(o2)(f2), O.some(O.none)); + assertEquals(apply(o2)(f3), O.some(O.none)); + assertEquals(apply(o3)(f1), O.none); + assertEquals(apply(o3)(f2), O.some(O.none)); + assertEquals(apply(o3)(f3), O.some(O.some([1, 2]))); +}); + +Deno.test("Applicable applyFirst", () => { + const applyFirst = A.applyFirst(O.ApplicableOption); + assertEquals(applyFirst(O.none)(O.none), O.none); + assertEquals(applyFirst(O.none)(O.some(1)), O.none); + assertEquals(applyFirst(O.some(2))(O.none), O.none); + assertEquals(applyFirst(O.some(2))(O.some(1)), O.some(1)); +}); + +Deno.test("Applicable applySecond", () => { + const applySecond = A.applySecond(O.ApplicableOption); + assertEquals(applySecond(O.none)(O.none), O.none); + assertEquals(applySecond(O.none)(O.some(1)), O.none); + assertEquals(applySecond(O.some(2))(O.none), O.none); + assertEquals(applySecond(O.some(2))(O.some(1)), O.some(2)); +}); diff --git a/testing/array.test.ts b/testing/array.test.ts index 62cac8d..050c9f1 100644 --- a/testing/array.test.ts +++ b/testing/array.test.ts @@ -113,8 +113,8 @@ Deno.test("Array flatmap", () => { ]); }); -Deno.test("Array reduce", () => { - assertEquals(pipe([1, 2, 3], A.reduce((a, b) => a + b, 0)), 6); +Deno.test("Array fold", () => { + assertEquals(pipe([1, 2, 3], A.fold((a, b) => a + b, 0)), 6); }); Deno.test("Array traverse", () => { @@ -128,7 +128,7 @@ Deno.test("Array indexedMap", () => { }); Deno.test("Array indexedReduce", () => { - assertEquals(pipe([1, 2, 3], A.reduce((a, b, i) => a + b + i, 0)), 9); + assertEquals(pipe([1, 2, 3], A.fold((a, b, i) => a + b + i, 0)), 9); }); Deno.test("Array indexedTraverse", () => { @@ -308,6 +308,11 @@ Deno.test("Array range", () => { assertEquals(A.range(-1, 1, 1), []); }); +Deno.test("Array getCombinableArray", () => { + const { combine } = A.getCombinableArray(); + assertStrictEquals(combine, A.combine); +}); + Deno.test("Array getComparableArray", () => { const eq = A.getComparableArray(ComparableBoolean); const values = [true, false]; @@ -354,3 +359,29 @@ Deno.test("Array getShowableArray", () => { assertEquals(show.show([]), "ReadonlyArray[]"); assertEquals(show.show([1, 2, 3]), "ReadonlyArray[1, 2, 3]"); }); + +Deno.test("Array tap", () => { + const out: number[] = []; + pipe( + A.range(3), + A.tap((n) => out.push(n)), + ); + assertEquals(out, A.range(3)); +}); + +Deno.test("Array bind", () => { + assertEquals( + pipe( + A.range(2), + A.bindTo("a"), + A.bind("b", ({ a }) => [a, a + 1]), + ), + [{ a: 0, b: 0 }, { a: 0, b: 1 }, { a: 1, b: 1 }, { a: 1, b: 2 }], + ); +}); + +Deno.test("Array bindTo", () => { + assertEquals(pipe(A.range(2), A.bindTo("range")), [{ range: 0 }, { + range: 1, + }]); +}); diff --git a/testing/async.test.ts b/testing/async.test.ts index a5ddcab..5095b3b 100644 --- a/testing/async.test.ts +++ b/testing/async.test.ts @@ -1,6 +1,7 @@ import { assertEquals } from "https://deno.land/std@0.103.0/testing/asserts.ts"; import * as A from "../async.ts"; +import * as N from "../number.ts"; import { pipe } from "../fn.ts"; const add = (n: number) => n + 1; @@ -64,21 +65,54 @@ Deno.test("Async apSeq", async () => { ); }); -// Deno.test("Async Do, bind, bindTo", () => { -// assertEquals( -// pipe( -// A.Do(), -// A.bind("one", () => A.wrap(1)), -// A.bind("two", ({ one }) => A.wrap(one + one)), -// A.map(({ one, two }) => one + two), -// ), -// A.wrap(3), -// ); -// assertEquals( -// pipe( -// A.wrap(1), -// A.bindTo("one"), -// ), -// A.wrap({ one: 1 }), -// ); -// }); +Deno.test("Async getCombinableAsync", async () => { + const { combine } = A.getCombinableAsync(N.InitializableNumberSum); + assertEquals( + await pipe( + A.wrap(1), + combine(A.wrap(2)), + )(), + 3, + ); +}); + +Deno.test("Async getInitializableAsync", async () => { + const { init, combine } = A.getInitializableAsync(N.InitializableNumberSum); + assertEquals(await init()(), 0); + assertEquals( + await pipe( + A.wrap(1), + combine(A.wrap(2)), + )(), + 3, + ); +}); + +Deno.test("Async tap", async () => { + let out: null | number = null; + await pipe( + A.wrap(1), + A.tap((n) => out = n), + )(); + assertEquals(out, 1); +}); + +Deno.test("Async bind", async () => { + assertEquals( + await pipe( + A.wrap({ a: 1 }), + A.bind("b", ({ a }) => A.wrap(a + 1)), + )(), + { a: 1, b: 2 }, + ); +}); + +Deno.test("Async bindTo", async () => { + assertEquals( + await pipe( + A.wrap(1), + A.bindTo("a"), + )(), + { a: 1 }, + ); +}); diff --git a/testing/async_iterable.test.ts b/testing/async_iterable.test.ts index ff86129..6aae2d6 100644 --- a/testing/async_iterable.test.ts +++ b/testing/async_iterable.test.ts @@ -149,11 +149,11 @@ Deno.test("AsyncIterable partitionMap", async () => { assertEquals(await AI.collect(second), [0, 1]); }); -Deno.test("AsyncIterable reduce", async () => { +Deno.test("AsyncIterable fold", async () => { assertEquals( await pipe( AI.range(3), - AI.reduce((value, sum) => value + sum, 0), + AI.fold((value, sum) => value + sum, 0), ), 3, ); diff --git a/testing/datum.test.ts b/testing/datum.test.ts index fc9a04a..6526725 100644 --- a/testing/datum.test.ts +++ b/testing/datum.test.ts @@ -290,13 +290,13 @@ Deno.test("Datum alt", () => { assertEquals(pipe(D.refresh(1), D.alt(D.refresh(2))), D.refresh(1)); }); -Deno.test("Datum reduce", () => { - const reduce = D.reduce((o: number, a: number) => o + a, 0); +Deno.test("Datum fold", () => { + const fold = D.fold((o: number, a: number) => o + a, 0); - assertEquals(reduce(D.initial), 0); - assertEquals(reduce(D.pending), 0); - assertEquals(reduce(D.replete(1)), 1); - assertEquals(reduce(D.refresh(1)), 1); + assertEquals(fold(D.initial), 0); + assertEquals(fold(D.pending), 0); + assertEquals(fold(D.replete(1)), 1); + assertEquals(fold(D.refresh(1)), 1); }); Deno.test("Datum traverse", () => { diff --git a/testing/decoder.test.ts b/testing/decoder.test.ts index cc33b0e..ba4fd1b 100644 --- a/testing/decoder.test.ts +++ b/testing/decoder.test.ts @@ -162,9 +162,9 @@ Deno.test("DecodeError match", () => { (_, err) => countErrors(err), (_, __, err) => countErrors(err), (_, __, err) => countErrors(err), - A.reduce((acc, err) => acc + countErrors(err), 0), - A.reduce((acc, err) => acc + countErrors(err), 0), - A.reduce((acc, err) => acc + countErrors(err), 0), + A.fold((acc, err) => acc + countErrors(err), 0), + A.fold((acc, err) => acc + countErrors(err), 0), + A.fold((acc, err) => acc + countErrors(err), 0), ); assertEquals(countErrors(leaf), 1); diff --git a/testing/either.test.ts b/testing/either.test.ts index a60d3ba..7506525 100644 --- a/testing/either.test.ts +++ b/testing/either.test.ts @@ -185,11 +185,11 @@ Deno.test("Either getRightInitializable", () => { assertEquals(Initializable.init(), E.right(N.InitializableNumberSum.init())); }); -Deno.test("Either reduce", () => { - const reduce = E.reduce((o: number, i: number) => o + i, 0); +Deno.test("Either fold", () => { + const fold = E.fold((o: number, i: number) => o + i, 0); - assertEquals(reduce(E.left("adsf")), 0); - assertEquals(reduce(E.right(1)), 1); + assertEquals(fold(E.left("adsf")), 0); + assertEquals(fold(E.right(1)), 1); }); Deno.test("Either map", () => { diff --git a/testing/foldable.test.ts b/testing/foldable.test.ts new file mode 100644 index 0000000..01904d7 --- /dev/null +++ b/testing/foldable.test.ts @@ -0,0 +1,11 @@ +import { assertEquals } from "https://deno.land/std@0.103.0/testing/asserts.ts"; + +import * as R from "../foldable.ts"; +import * as A from "../array.ts"; +import * as N from "../number.ts"; + +Deno.test("Foldable collect", () => { + const collect = R.collect(A.FoldableArray, N.InitializableNumberSum); + assertEquals(collect([]), 0); + assertEquals(collect([1, 2, 3, 4]), 10); +}); diff --git a/testing/free.test.ts b/testing/free.test.ts index 4fb3baa..5b83c0e 100644 --- a/testing/free.test.ts +++ b/testing/free.test.ts @@ -112,9 +112,9 @@ Deno.test("Free apply", () => { ); }); -Deno.test("Free reduce", () => { +Deno.test("Free fold", () => { assertEquals( - pipe(F.link(F.node(1), F.node(1)), F.reduce((n, m) => n + m, 0)), + pipe(F.link(F.node(1), F.node(1)), F.fold((n, m) => n + m, 0)), 2, ); }); diff --git a/testing/iterable.test.ts b/testing/iterable.test.ts index 9bccf4a..3da05af 100644 --- a/testing/iterable.test.ts +++ b/testing/iterable.test.ts @@ -73,11 +73,11 @@ Deno.test("Iterable forEach", () => { assertEquals(results, [0, 1, 2]); }); -Deno.test("Iterable reduce", () => { +Deno.test("Iterable fold", () => { assertEquals( pipe( I.range(3), - I.reduce((n, m) => n + m, 0), + I.fold((n, m) => n + m, 0), ), 3, ); diff --git a/testing/map.test.ts b/testing/map.test.ts index d3832e3..aa73f9e 100644 --- a/testing/map.test.ts +++ b/testing/map.test.ts @@ -3,7 +3,7 @@ import { assertEquals } from "https://deno.land/std/testing/asserts.ts"; import * as M from "../map.ts"; import * as O from "../option.ts"; import * as N from "../number.ts"; -import * as R from "../reducible.ts"; +import * as R from "../foldable.ts"; import { pipe } from "../fn.ts"; Deno.test("Map init", () => { @@ -97,8 +97,8 @@ Deno.test("Map values", () => { assertEquals(pipe(tb, values), []); }); -Deno.test("Map reduce", () => { - const collect = R.collect(M.ReducibleMap, N.InitializableNumberSum); +Deno.test("Map fold", () => { + const collect = R.collect(M.FoldableMap, N.InitializableNumberSum); assertEquals(collect(M.readonlyMap()), 0); assertEquals(collect(M.readonlyMap([1, 1], [2, 2], [3, 3])), 6); }); diff --git a/testing/option.test.ts b/testing/option.test.ts index fd0d0ed..c023c57 100644 --- a/testing/option.test.ts +++ b/testing/option.test.ts @@ -108,10 +108,10 @@ Deno.test("Option flatmap", () => { assertEquals(pipe(O.none, O.flatmap(fati)), O.none); }); -Deno.test("Option reduce", () => { - const reduce = O.reduce((n: number, o: number) => n + o, 0); - assertEquals(reduce(O.some(1)), 1); - assertEquals(reduce(O.none), 0); +Deno.test("Option fold", () => { + const fold = O.fold((n: number, o: number) => n + o, 0); + assertEquals(fold(O.some(1)), 1); + assertEquals(fold(O.none), 0); }); Deno.test("Option traverse", () => { diff --git a/testing/pair.test.ts b/testing/pair.test.ts index 2d9aeaf..1342211 100644 --- a/testing/pair.test.ts +++ b/testing/pair.test.ts @@ -71,9 +71,9 @@ Deno.test("Pair unwrap", () => { assertEquals(P.unwrap(P.pair(1, 2)), 1); }); -Deno.test("Pair reduce", () => { +Deno.test("Pair fold", () => { assertEquals( - pipe(P.pair(10, 20), P.reduce(Math.max, Number.NEGATIVE_INFINITY)), + pipe(P.pair(10, 20), P.fold(Math.max, Number.NEGATIVE_INFINITY)), 20, ); }); @@ -99,12 +99,12 @@ Deno.test("Pair BimappablePair", () => { assertStrictEquals(P.BimappablePair.mapSecond, P.mapSecond); }); -Deno.test("Pair ReduciblePair", () => { - assertStrictEquals(P.ReduciblePair.reduce, P.reduce); +Deno.test("Pair FoldablePair", () => { + assertStrictEquals(P.FoldablePair.fold, P.fold); }); Deno.test("Pair TraversablePair", () => { - assertStrictEquals(P.TraversablePair.reduce, P.reduce); + assertStrictEquals(P.TraversablePair.fold, P.fold); assertStrictEquals(P.TraversablePair.traverse, P.traverse); assertStrictEquals(P.TraversablePair.map, P.map); }); diff --git a/testing/record.test.ts b/testing/record.test.ts index 3f0cdf5..78fedd7 100644 --- a/testing/record.test.ts +++ b/testing/record.test.ts @@ -68,18 +68,18 @@ Deno.test("Record map", () => { assertEquals(indexedMap({ a: 0, b: 2 }), { a: 1, b: 3 }); }); -Deno.test("Record reduce", () => { +Deno.test("Record fold", () => { assertEquals( - pipe({ a: 1, b: 2 }, R.reduce((a: number, b: number) => a + b, 0)), + pipe({ a: 1, b: 2 }, R.fold((a: number, b: number) => a + b, 0)), 3, ); - assertEquals(pipe({}, R.reduce(add, 0)), 0); + assertEquals(pipe({}, R.fold(add, 0)), 0); - const reduce = R.reduce((a: number, c: number) => a + c, 0); - assertEquals(reduce({}), 0); - assertEquals(reduce({ a: 1, b: 2 }), 3); + const fold = R.fold((a: number, c: number) => a + c, 0); + assertEquals(fold({}), 0); + assertEquals(fold({ a: 1, b: 2 }), 3); - const indexedReduce = R.reduce( + const indexedReduce = R.fold( (o: string[], a: number, i: string) => a === 0 ? [...o, i] : [...o, a.toString()], [], @@ -263,7 +263,7 @@ Deno.test("Record FunctoRecord", () => { Deno.test("Record TraversableRecord", () => { assertStrictEquals(R.TraversableRecord.map, R.map); - assertStrictEquals(R.TraversableRecord.reduce, R.reduce); + assertStrictEquals(R.TraversableRecord.fold, R.fold); assertStrictEquals(R.TraversableRecord.traverse, R.traverse); }); diff --git a/testing/set.test.ts b/testing/set.test.ts index 365184d..b326e7f 100644 --- a/testing/set.test.ts +++ b/testing/set.test.ts @@ -130,10 +130,10 @@ Deno.test("Set partitionMap", () => { assertEquals(partitionMap(set), [S.set(2, 3), S.set(1)]); }); -Deno.test("Set reduce", () => { - const reduce = S.reduce((n: number, o: number) => n + o, 0); - assertEquals(reduce(S.init()), 0); - assertEquals(reduce(S.set(1, 2, 3)), 6); +Deno.test("Set fold", () => { + const fold = S.fold((n: number, o: number) => n + o, 0); + assertEquals(fold(S.init()), 0); + assertEquals(fold(S.set(1, 2, 3)), 6); }); Deno.test("Set traverse", () => { @@ -170,7 +170,7 @@ Deno.test("Set FilterableSet", () => { Deno.test("Set TraversableSet", () => { assertStrictEquals(S.TraversableSet.map, S.map); - assertStrictEquals(S.TraversableSet.reduce, S.reduce); + assertStrictEquals(S.TraversableSet.fold, S.fold); assertStrictEquals(S.TraversableSet.traverse, S.traverse); }); diff --git a/testing/sync.test.ts b/testing/sync.test.ts index 052b41f..a0a51d6 100644 --- a/testing/sync.test.ts +++ b/testing/sync.test.ts @@ -28,9 +28,9 @@ Deno.test("Sync flatmap", () => { assertEqualsSync(flatmap(S.wrap(1)), S.wrap(2)); }); -Deno.test("Sync reduce", () => { - const reduce = S.reduce((acc: number, cur: number) => acc + cur, 0); - assertEquals(reduce(S.wrap(1)), 1); +Deno.test("Sync fold", () => { + const fold = S.fold((acc: number, cur: number) => acc + cur, 0); + assertEquals(fold(S.wrap(1)), 1); }); Deno.test("Sync traverse", () => { diff --git a/testing/sync_either.test.ts b/testing/sync_either.test.ts index fe90639..fd5737d 100644 --- a/testing/sync_either.test.ts +++ b/testing/sync_either.test.ts @@ -74,11 +74,11 @@ Deno.test("SyncEither mapSecond", () => { assertEqualsIO(mapSecond(SE.right(0)), SE.right(0)); }); -Deno.test("SyncEither reduce", () => { - const reduce = SE.reduce((a: number, c: number) => a + c, 0); +Deno.test("SyncEither fold", () => { + const fold = SE.fold((a: number, c: number) => a + c, 0); - assertEquals(reduce(SE.left(-1)), 0); - assertEquals(reduce(SE.right(1)), 1); + assertEquals(fold(SE.left(-1)), 0); + assertEquals(fold(SE.right(1)), 1); }); Deno.test("SyncEither alt", () => { diff --git a/testing/these.test.ts b/testing/these.test.ts index 7a4c022..ee6963c 100644 --- a/testing/these.test.ts +++ b/testing/these.test.ts @@ -67,11 +67,11 @@ Deno.test("These map", () => { assertEquals(map(T.both(1, 1)), T.both(1, 2)); }); -Deno.test("These reduce", () => { - const reduce = T.reduce((n: number, m: number) => n + m, 0); - assertEquals(reduce(T.left(1)), 0); - assertEquals(reduce(T.right(1)), 1); - assertEquals(reduce(T.both(1, 1)), 1); +Deno.test("These fold", () => { + const fold = T.fold((n: number, m: number) => n + m, 0); + assertEquals(fold(T.left(1)), 0); + assertEquals(fold(T.right(1)), 1); + assertEquals(fold(T.both(1, 1)), 1); }); Deno.test("These traverse", () => { diff --git a/testing/tree.test.ts b/testing/tree.test.ts index 1b933d4..7a031f0 100644 --- a/testing/tree.test.ts +++ b/testing/tree.test.ts @@ -56,10 +56,10 @@ Deno.test("Tree flatmap", () => { assertEquals(flatmap(T.wrap(0)), T.wrap(0)); }); -Deno.test("Tree reduce", () => { - const reduce = T.reduce((n: number, i: number) => n + i, 0); - assertEquals(reduce(T.wrap(1)), 1); - assertEquals(reduce(T.wrap(1, [T.wrap(2)])), 3); +Deno.test("Tree fold", () => { + const fold = T.fold((n: number, i: number) => n + i, 0); + assertEquals(fold(T.wrap(1)), 1); + assertEquals(fold(T.wrap(1, [T.wrap(2)])), 3); }); Deno.test("Tree traverse", () => { diff --git a/these.ts b/these.ts index 4392e74..f0e44eb 100644 --- a/these.ts +++ b/these.ts @@ -4,7 +4,7 @@ import type { Bimappable } from "./bimappable.ts"; import type { Combinable } from "./combinable.ts"; import type { Flatmappable } from "./flatmappable.ts"; import type { Mappable } from "./mappable.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; import type { Showable } from "./showable.ts"; import type { Traversable } from "./traversable.ts"; @@ -88,7 +88,7 @@ export function mapSecond( ); } -export function reduce( +export function fold( foao: (o: O, a: A) => O, o: O, ): (ta: These) => O { @@ -112,11 +112,11 @@ export const BimappableThese: Bimappable = { map, mapSecond }; export const MappableThese: Mappable = { map }; -export const ReducibleThese: Reducible = { reduce }; +export const FoldableThese: Foldable = { fold }; export const TraversableThese: Traversable = { map, - reduce, + fold, traverse, }; diff --git a/traversable.ts b/traversable.ts index de00cf9..5e8752a 100644 --- a/traversable.ts +++ b/traversable.ts @@ -4,23 +4,23 @@ * turning an Array> into Option> or as complicated * as creating all combinations of numbers in three Array. * - * @module Mappable + * @module Traversable * @since 2.0.0 */ import type { $, Hold, Kind } from "./kind.ts"; import type { Applicable } from "./applicable.ts"; import type { Mappable } from "./mappable.ts"; -import type { Reducible } from "./reducible.ts"; +import type { Foldable } from "./foldable.ts"; /** - * A Traversable structure extends Mappable and Reducible. It contains the - * methods map, reduce, and traverse. + * A Traversable structure extends Mappable and Foldable. It contains the + * methods map, fold, and traverse. * * @since 2.0.0 */ export interface Traversable - extends Mappable, Reducible, Hold { + extends Mappable, Foldable, Hold { readonly traverse: ( A: Applicable, ) => ( diff --git a/tree.ts b/tree.ts index 5807feb..6ea7099 100644 --- a/tree.ts +++ b/tree.ts @@ -135,16 +135,16 @@ export function apply(ua: Tree): (tfai: Tree<(a: A) => I>) => Tree { } /** - * The reduce function for Reducible. + * The fold function for Foldable. * * @since 2.0.0 */ -export function reduce( +export function fold( foao: (o: O, a: A) => O, o: O, ): (ta: Tree) => O { - const reducer = (result: O, tree: Tree) => reduce(foao, result)(tree); - return (ta) => TraversableArray.reduce(reducer, foao(o, ta.value))(ta.forest); + const foldr = (result: O, tree: Tree) => fold(foao, result)(tree); + return (ta) => TraversableArray.fold(foldr, foao(o, ta.value))(ta.forest); } /** @@ -270,7 +270,7 @@ export const MappableTree: Mappable = { map }; /** * @since 2.0.0 */ -export const TraversableTree: Traversable = { map, reduce, traverse }; +export const TraversableTree: Traversable = { map, fold, traverse }; /** * @since 2.0.0