Skip to content

Commit

Permalink
NonEmptyTraversable: add sequenceNonEmpty as member
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti authored and mikearnaldi committed Oct 28, 2022
1 parent 9d4ac0b commit fc914c9
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-seas-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fp-ts/core": patch
---

NonEmptyTraversable: add sequenceNonEmpty as member
3 changes: 2 additions & 1 deletion Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,9 @@ instance instead of `Applicative`.
| Name | Given | To |
| --------------------------- | ------------------------------------------------ | ------------ |
| **traverseNonEmpty** | `NonEmptyApplicative<F>`, `T<A>`, `A => F<B>` | `F<T<B>>` |
| **sequenceNonEmpty** | `NonEmptyApplicative<F>`, `T<F<A>>` | `F<T<A>>` |
| traverseNonEmptyComposition | `NonEmptyApplicative<F>`, `T<G<A>>`, `A => F<B>` | `F<T<G<B>>>` |
| sequenceNonEmpty | `NonEmptyApplicative<F>`, `T<F<A>>` | `F<T<A>>` |
| sequenceNonEmptyComposition | `NonEmptyApplicative<F>`, `T<G<F<A>>>` | `F<T<G<A>>>` |

### Of

Expand Down
34 changes: 30 additions & 4 deletions src/typeclass/NonEmptyTraversable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* @since 1.0.0
*/
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 { Covariant } from "@fp-ts/core/typeclass/Covariant"
import type { NonEmptyApplicative } from "@fp-ts/core/typeclass/NonEmptyApplicative"

/**
Expand All @@ -19,6 +20,12 @@ export interface NonEmptyTraversable<T extends TypeLambda> extends TypeClass<T>
) => <TR, TO, TE>(
self: Kind<T, TR, TO, TE, A>
) => Kind<F, R, O, E, Kind<T, TR, TO, TE, B>>

readonly sequenceNonEmpty: <F extends TypeLambda>(
F: NonEmptyApplicative<F>
) => <TR, TO, TE, R, O, E, A>(
self: Kind<T, TR, TO, TE, Kind<F, R, O, E, A>>
) => Kind<F, R, O, E, Kind<T, TR, TO, TE, A>>
}

/**
Expand All @@ -34,16 +41,35 @@ export const traverseNonEmptyComposition = <T extends TypeLambda, F extends Type
<A, R, O, E, B>(
f: (a: A) => Kind<G, R, O, E, B>
): (<TR, TO, TE, GR, GO, GE>(
tfa: Kind<T, TR, TO, TE, Kind<F, GR, GO, GE, A>>
self: Kind<T, TR, TO, TE, Kind<F, GR, GO, GE, A>>
) => Kind<G, R, O, E, Kind<T, TR, TO, TE, Kind<F, GR, GO, GE, B>>>) =>
T.traverseNonEmpty(F)(G.traverseNonEmpty(F)(f))

/**
* Returns a default `sequenceNonEmpty` composition.
*
* @since 1.0.0
*/
export const sequenceNonEmptyComposition = <T extends TypeLambda, F extends TypeLambda>(
T: NonEmptyTraversable<T> & Covariant<T>,
G: NonEmptyTraversable<F>
) =>
<G extends TypeLambda>(F: NonEmptyApplicative<G>) =>
<TR, TO, TE, GR, GO, GE, R, O, E, A>(
self: Kind<T, TR, TO, TE, Kind<F, GR, GO, GE, Kind<G, R, O, E, A>>>
): Kind<G, R, O, E, Kind<T, TR, TO, TE, Kind<F, GR, GO, GE, A>>> =>
T.sequenceNonEmpty(F)(pipe(self, T.map(G.sequenceNonEmpty(F))))

/**
* Returns a default `sequenceNonEmpty` implementation.
*
* @since 1.0.0
*/
export const sequenceNonEmpty = <T extends TypeLambda>(T: NonEmptyTraversable<T>) =>
export const sequenceNonEmpty = <T extends TypeLambda>(
traverseNonEmpty: NonEmptyTraversable<T>["traverseNonEmpty"]
): NonEmptyTraversable<T>["sequenceNonEmpty"] =>
<F extends TypeLambda>(
F: NonEmptyApplicative<F>
): (<TR, TO, TE, R, O, E, A>(
self: Kind<T, TR, TO, TE, Kind<F, R, O, E, A>>
) => Kind<F, R, O, E, Kind<T, TR, TO, TE, A>>) => T.traverseNonEmpty(F)(identity)
) => Kind<F, R, O, E, Kind<T, TR, TO, TE, A>>) => traverseNonEmpty(F)(identity)
12 changes: 10 additions & 2 deletions test/test-data/NonEmptyReadonlyArray.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Kind, TypeLambda } from "@fp-ts/core/HKT"
import { pipe } from "@fp-ts/core/internal/Function"
import { identity, pipe } from "@fp-ts/core/internal/Function"
import * as covariant from "@fp-ts/core/typeclass/Covariant"
import type { NonEmptyApplicative } from "@fp-ts/core/typeclass/NonEmptyApplicative"
import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable"

Expand Down Expand Up @@ -34,6 +35,10 @@ export const mapWithIndex = <A, B>(
return out
}

export const map = <A, B>(
f: (a: A) => B
): (self: NonEmptyReadonlyArray<A>) => NonEmptyReadonlyArray<B> => mapWithIndex(f)

export const traverseWithIndex = <F extends TypeLambda>(
NonEmptyApplicative: NonEmptyApplicative<F>
) =>
Expand All @@ -54,8 +59,11 @@ export const traverseNonEmpty = <F extends TypeLambda>(
): ((self: NonEmptyReadonlyArray<A>) => Kind<F, R, O, E, NonEmptyReadonlyArray<B>>) =>
traverseWithIndex(NonEmptyApplicative)(f)

export const Covariant: covariant.Covariant<NonEmptyReadonlyArrayTypeLambda> = covariant.make(map)

export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable<
NonEmptyReadonlyArrayTypeLambda
> = {
traverseNonEmpty
traverseNonEmpty,
sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity))
}
18 changes: 17 additions & 1 deletion test/typeclass/NonEmptyTraversable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,24 @@ describe("NonEmptyTraversable", () => {
U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, -1]]), O.none)
})

it("traverseNonEmptyComposition", () => {
const sequence = _.sequenceNonEmptyComposition(
{ ...NERA.NonEmptyTraversable, ...NERA.Covariant },
NERA.NonEmptyTraversable
)(O.NonEmptyApplicative)
U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]] as const))
U.deepStrictEqual(sequence([[O.some(1), O.none]]), O.none)
U.deepStrictEqual(
sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.some(5)]]),
O.some([[1, 2, 3], [4, 5]] as const)
)
U.deepStrictEqual(sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.none]]), O.none)
})

it("sequenceNonEmpty", () => {
const sequenceNonEmpty = _.sequenceNonEmpty(NERA.NonEmptyTraversable)(O.NonEmptyApplicative)
const sequenceNonEmpty = _.sequenceNonEmpty<NERA.NonEmptyReadonlyArrayTypeLambda>(
NERA.NonEmptyTraversable.traverseNonEmpty
)(O.NonEmptyApplicative)
U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none)
U.deepStrictEqual(sequenceNonEmpty([O.some(1)]), O.some([1] as const))
U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none)
Expand Down

0 comments on commit fc914c9

Please sign in to comment.