Skip to content

Commit

Permalink
feat(either): traverse
Browse files Browse the repository at this point in the history
  • Loading branch information
Hfutsora committed Jul 27, 2022
1 parent 33c71c3 commit fd275e4
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 9 deletions.
20 changes: 16 additions & 4 deletions src/Either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Alt2 } from './Functors/Alt'
import { ChainRec2, tailRec } from './Functors/ChainRec'
import { Comonad2 } from './Functors/Comonad'
import { Extend2 } from './Functors/Extend'
import { Traversable2 } from './Functors/Traversable'
import { Traversable2, PipeableTraverse2 } from './Functors/Traversable'
import { Applicative } from './Functors/Applicative'
import { HKT } from './Functors/HKT'

Expand Down Expand Up @@ -258,10 +258,22 @@ export const reduce = <E, A, B>(f: (acc: B, a: A) => B, b: B) => (ma: Either<E,
isLeft(ma) ? b : f(b, ma.right)

/**
* TODO:
* Maps each element of a `HKT` structure to an action, and collects the results wrapped in `Right`.
*
* Returns a `HKT` contains a left with the value of `Either` if the `Either` is a `Left`.
*
* @example
*
* ```ts
* const f = traverse(Maybe.Monad)((n: number) => n > 0 ? some(n): none)
* assert.deepStrictEqual(pipe(left('err'), f), some(left('err')))
* assert.deepStrictEqual(pipe(right(1), f), some(right(1)))
* assert.deepStrictEqual(pipe(right(-1), f), none)
* ```
*/
export const traverse: <F>(F: Applicative<F>) => <A, B>(f: (a: A) => HKT<F, B>) => <E>(e: Either<E, A>) => HKT<F, Either<E, B>> =
F => f => e => isLeft(e) ? F.of(left(e.left)) : F.map(f(e.right), right)
export const traverse: PipeableTraverse2<EitherKind> =
<F>(F: Applicative<F>): <A, B>(f: (a: A) => HKT<F, B>) => <E>(e: Either<E, A>) => HKT<F, Either<E, B>> =>
f => e => isLeft(e) ? F.of(left(e.left)) : F.map(f(e.right), right)

/**
* Returns `Either` if it's a `Right`, otherwise returns onLeft result.
Expand Down
12 changes: 9 additions & 3 deletions src/Functors/Traversable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import { HKT, KindOf, URIS } from './HKT'
import { Functor, Functor1, Functor2 } from './Functor'
import { Foldable, Foldable1, Foldable2 } from './Foldable'
import { Applicative, Applicative2 } from './Applicative'
import { Applicative, Applicative1, Applicative2 } from './Applicative'

export interface Traversable<F> extends Functor<F>, Foldable<F> {
readonly traverse: <T>(A: Applicative<T>) => <A, B>(ma: HKT<F, A>, f: (a: A) => HKT<T, B>) => HKT<F, B>
Expand All @@ -29,12 +29,18 @@ export interface Traversable2<F extends URIS> extends Functor2<F>, Foldable2<F>

export interface Traverse<T extends URIS> {
<F extends URIS>(F: Applicative2<F>): <A, E, B>(ma: KindOf<T, [A]>, f: (a: A) => KindOf<F, [E, B]>) => KindOf<F, [E, KindOf<T, [B]>]>
<F extends URIS>(F: Applicative<F>): <A, B>(ma: KindOf<T, [A]>, f: (a: A) => KindOf<F, [B]>) => KindOf<F, [KindOf<T, [B]>]>
<F extends URIS>(F: Applicative1<F>): <A, B>(ma: KindOf<T, [A]>, f: (a: A) => KindOf<F, [B]>) => KindOf<F, [KindOf<T, [B]>]>
<F>(F: Applicative<F>): <A, B>(ma: KindOf<T, [A]>, f: (a: A) => HKT<F, B>) => HKT<F, KindOf<T, [B]>>
}

export interface Traverse2<T extends URIS> {
<F extends URIS>(F: Applicative2<F>): <E, A, FE, B>(ma: KindOf<T, [E, A]>, f: (a: A) => KindOf<F, [FE, B]>) => KindOf<F, [FE, KindOf<T, [E, B]>]>
<F extends URIS>(F: Applicative<F>): <E, A, B>(ma: KindOf<T, [E, A]>, f: (a: A) => KindOf<F, [B]>) => KindOf<F, [KindOf<T, [E, B]>]>
<F extends URIS>(F: Applicative1<F>): <E, A, B>(ma: KindOf<T, [E, A]>, f: (a: A) => KindOf<F, [B]>) => KindOf<F, [KindOf<T, [E, B]>]>
<F>(F: Applicative<F>): <E, A, B>(ma: KindOf<T, [E, A]>, f: (a: A) => HKT<F, B>) => HKT<F, KindOf<T, [E, B]>>
}

export interface PipeableTraverse2<T extends URIS> {
<F extends URIS>(F: Applicative2<F>): <A, FE, B>(f: (a: A) => KindOf<F, [FE, B]>) => <TE>(ta: KindOf<T, [TE, A]>) => KindOf<F, [FE, KindOf<T, [TE, B]>]>
<F extends URIS>(F: Applicative1<F>): <A, B>(f: (a: A) => KindOf<F, [B]>) => <TE>(ta: KindOf<T, [TE, A]>) => KindOf<F, [KindOf<T, [TE, B]>]>
<F>(F: Applicative<F>): <A, B>(f: (a: A) => HKT<F, B>) => <TE>(ta: KindOf<T, [TE, A]>) => HKT<F, KindOf<T, [TE, B]>>
}
8 changes: 6 additions & 2 deletions test/Either.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {
isLeft, left, right, isRight, map, of, fromPredicate, match, getOrElse, chain, orElse, exists, alt, getLeft, getRight,
fromMaybe, tryCatch, swap, equals, ap, chainRec, extend, extract, reduce, traverse, filterOrElse } from '../src/Either'
import { flow, pipe } from '../src/Pipe'
import { none, some } from '../src/Maybe'
import { none, some, Monad as MM } from '../src/Maybe'


test('isLeft', () => {
expect(isLeft(left(0))).toBeTruthy()
Expand Down Expand Up @@ -130,7 +131,10 @@ test('reduce', () => {
})

test('traverse', () => {
// TODO:
const f = traverse(MM)((n: number) => n > 0 ? some(n): none)
expect(pipe(left('err'), f)).toEqual(some(left('err')))
expect(pipe(right(1), f)).toEqual(some(right(1)))
expect(pipe(right(-1), f)).toEqual(none)
})

test('orElse', () => {
Expand Down

0 comments on commit fd275e4

Please sign in to comment.