Skip to content

Commit

Permalink
Foldable / FoldableWithIndex: add compositions
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti authored and mikearnaldi committed Oct 17, 2022
1 parent 2d30a18 commit ae9715f
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/fuzzy-mugs-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fp-ts/core": patch
---

Foldable / FoldableWithIndex: add compositions
30 changes: 29 additions & 1 deletion src/Foldable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT"
import { identity } from "@fp-ts/core/internal/Function"
import { identity, pipe } from "@fp-ts/core/internal/Function"
import type { Monoid } from "@fp-ts/core/Monoid"

/**
Expand All @@ -22,6 +22,34 @@ export interface Foldable<F extends TypeLambda> extends TypeClass<F> {
) => <S, R, O, E>(self: Kind<F, S, R, O, E, A>) => B
}

/**
* Returns a default `reduce` composition.
*
* @since 1.0.0
*/
export const reduceComposition = <F extends TypeLambda, G extends TypeLambda>(
F: Foldable<F>,
G: Foldable<G>
) =>
<B, A>(b: B, f: (b: B, a: A) => B) =>
<FS, FR, FO, FE, GS, GR, GO, GE>(
self: Kind<F, FS, FR, FO, FE, Kind<G, GS, GR, GO, GE, A>>
): B => pipe(self, F.reduce(b, (b, ga) => pipe(ga, G.reduce(b, f))))

/**
* Returns a default `reduceRight` composition.
*
* @since 1.0.0
*/
export const reduceRightComposition = <F extends TypeLambda, G extends TypeLambda>(
F: Foldable<F>,
G: Foldable<G>
) =>
<B, A>(b: B, f: (b: B, a: A) => B) =>
<FS, FR, FO, FE, GS, GR, GO, GE>(
self: Kind<F, FS, FR, FO, FE, Kind<G, GS, GR, GO, GE, A>>
): B => pipe(self, F.reduceRight(b, (b, ga) => pipe(ga, G.reduceRight(b, f))))

/**
* @since 1.0.0
*/
Expand Down
40 changes: 39 additions & 1 deletion src/FoldableWithIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT"
import { identity } from "@fp-ts/core/internal/Function"
import { identity, pipe } from "@fp-ts/core/internal/Function"
import type { Monoid } from "@fp-ts/core/Monoid"

/**
Expand All @@ -22,6 +22,44 @@ export interface FoldableWithIndex<F extends TypeLambda, I> extends TypeClass<F>
) => <S, R, O, E>(self: Kind<F, S, R, O, E, A>) => B
}

/**
* Returns a default `reduceWithIndex` composition.
*
* @since 1.0.0
*/
export const reduceWithIndexComposition = <F extends TypeLambda, I, G extends TypeLambda, J>(
F: FoldableWithIndex<F, I>,
G: FoldableWithIndex<G, J>
) =>
<B, A>(b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) =>
<FS, FR, FO, FE, GS, GR, GO, GE>(
self: Kind<F, FS, FR, FO, FE, Kind<G, GS, GR, GO, GE, A>>
): B =>
pipe(
self,
F.reduceWithIndex(b, (b, ga, i) =>
pipe(ga, G.reduceWithIndex(b, (b, a, j) => f(b, a, [i, j]))))
)

/**
* Returns a default `reduceRightWithIndex` composition.
*
* @since 1.0.0
*/
export const reduceRightWithIndexComposition = <F extends TypeLambda, I, G extends TypeLambda, J>(
F: FoldableWithIndex<F, I>,
G: FoldableWithIndex<G, J>
) =>
<B, A>(b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) =>
<FS, FR, FO, FE, GS, GR, GO, GE>(
self: Kind<F, FS, FR, FO, FE, Kind<G, GS, GR, GO, GE, A>>
): B =>
pipe(
self,
F.reduceRightWithIndex(b, (b, ga, i) =>
pipe(ga, G.reduceRightWithIndex(b, (b, a, j) => f(b, a, [i, j]))))
)

/**
* @since 1.0.0
*/
Expand Down
19 changes: 19 additions & 0 deletions test/Foldable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ import * as RA from "./data/ReadonlyArray"
import * as U from "./util"

describe("Foldable", () => {
it("reduceComposition", () => {
const reduce = foldable.reduceComposition(RA.Foldable, RA.Foldable)
const f = (b: string, a: string) => b + a
U.deepStrictEqual(pipe([], reduce("-", f)), "-")
U.deepStrictEqual(pipe([[]], reduce("-", f)), "-")
U.deepStrictEqual(pipe([["a", "c"], ["b", "d"]], reduce("-", f)), "-acbd")
})

it("reduceRightComposition", () => {
const reduceRight = foldable.reduceRightComposition(RA.Foldable, RA.Foldable)
const f = (b: string, a: string) => b + a
U.deepStrictEqual(pipe([], reduceRight("-", f)), "-")
U.deepStrictEqual(pipe([[]], reduceRight("-", f)), "-")
U.deepStrictEqual(
pipe([["a", "c"], ["b", "d"]], reduceRight("-", f)),
"-dbca"
)
})

it("toReadonlyArray", () => {
const toReadonlyArray = foldable.toReadonlyArray(O.Foldable)
U.deepStrictEqual(toReadonlyArray(O.none), [])
Expand Down
30 changes: 29 additions & 1 deletion test/FoldableWithIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,35 @@ import * as O from "./data/Option"
import * as RA from "./data/ReadonlyArray"
import * as U from "./util"

describe("Foldable", () => {
describe("FoldableWithIndex", () => {
it("reduceWithIndexComposition", () => {
const reduceWithIndex = foldableWithIndex.reduceWithIndexComposition(
RA.FoldableWithIndex,
RA.FoldableWithIndex
)
const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j
U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-")
U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-")
U.deepStrictEqual(
pipe([["a", "c"], ["b", "d"]], reduceWithIndex("-", f)),
"-a00c01b10d11"
)
})

it("reduceRightWithIndexComposition", () => {
const reduceRightWithIndex = foldableWithIndex.reduceRightWithIndexComposition(
RA.FoldableWithIndex,
RA.FoldableWithIndex
)
const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j
U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-")
U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-")
U.deepStrictEqual(
pipe([["a", "c"], ["b", "d"]], reduceRightWithIndex("-", f)),
"-d11b10c01a00"
)
})

it("toReadonlyArray", () => {
const toReadonlyArray = foldableWithIndex.toReadonlyArray(O.FoldableWithIndex)
U.deepStrictEqual(toReadonlyArray(O.none), [])
Expand Down

0 comments on commit ae9715f

Please sign in to comment.