Skip to content

Commit

Permalink
Add Either.filterOrLeft (#1694)
Browse files Browse the repository at this point in the history
Co-authored-by: Przemyslaw Horban <p.horban@invinets.com>
  • Loading branch information
extremegf and Przemyslaw Horban authored Nov 28, 2023
1 parent ff6fadb commit 33ffa62
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/famous-news-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

Add Either.filterOrLeft
60 changes: 60 additions & 0 deletions docs/modules/Either.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Added in v2.0.0
- [getEquivalence](#getequivalence)
- [error handling](#error-handling)
- [orElse](#orelse)
- [filtering & conditionals](#filtering--conditionals)
- [filterOrLeft](#filterorleft)
- [generators](#generators)
- [gen](#gen)
- [getters](#getters)
Expand Down Expand Up @@ -252,6 +254,64 @@ export declare const orElse: {
Added in v2.0.0
# filtering & conditionals
## filterOrLeft
Filter the right value with the provided function.
If the predicate fails, set the left value with the result of the provided function.
**Signature**
```ts
export declare const filterOrLeft: {
<A, B extends A, X extends A, E2>(
filter: Refinement<A, B>,
orLeftWith: (a: X) => E2
): <E>(self: Either<E, A>) => Either<E2 | E, B>
<A, X extends A, Y extends A, E2>(
filter: Predicate<X>,
orLeftWith: (a: Y) => E2
): <E>(self: Either<E, A>) => Either<E2 | E, A>
<E, A, B extends A, X extends A, E2>(
self: Either<E, A>,
filter: Refinement<A, B>,
orLeftWith: (a: X) => E2
): Either<E | E2, B>
<E, A, X extends A, Y extends A, E2>(
self: Either<E, A>,
filter: Predicate<X>,
orLeftWith: (a: Y) => E2
): Either<E | E2, A>
}
```
**Example**
```ts
import * as E from "effect/Either"
import { pipe } from "effect/Function"

const isPositive = (n: number): boolean => n > 0

assert.deepStrictEqual(
pipe(
E.right(1),
E.filterOrLeft(isPositive, (n) => `${n} is not positive`)
),
E.right(1)
)
assert.deepStrictEqual(
pipe(
E.right(0),
E.filterOrLeft(isPositive, (n) => `${n} is not positive`)
),
E.left("0 is not positive")
)
```

Added in v2.0.0

# generators

## gen
Expand Down
54 changes: 54 additions & 0 deletions src/Either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { Inspectable } from "./Inspectable.js"
import * as either from "./internal/either.js"
import type { Option } from "./Option.js"
import type { Pipeable } from "./Pipeable.js"
import type { Predicate, Refinement } from "./Predicate.js"
import { isFunction } from "./Predicate.js"
import type * as Types from "./Types.js"
import type * as Unify from "./Unify.js"
Expand Down Expand Up @@ -375,6 +376,59 @@ export const match: {
}): B | C => isLeft(self) ? onLeft(self.left) : onRight(self.right)
)

/**
* Filter the right value with the provided function.
* If the predicate fails, set the left value with the result of the provided function.
*
* @example
* import * as E from 'effect/Either'
* import { pipe } from 'effect/Function'
*
* const isPositive = (n: number): boolean => n > 0
*
* assert.deepStrictEqual(
* pipe(
* E.right(1),
* E.filterOrLeft(isPositive, n => `${n} is not positive`)
* ),
* E.right(1)
* )
* assert.deepStrictEqual(
* pipe(
* E.right(0),
* E.filterOrLeft(isPositive, n => `${n} is not positive`)
* ),
* E.left("0 is not positive")
* )
*
* @since 2.0.0
* @category filtering & conditionals
*/
export const filterOrLeft: {
<A, B extends A, X extends A, E2>(
filter: Refinement<A, B>,
orLeftWith: (a: X) => E2
): <E>(self: Either<E, A>) => Either<E2 | E, B>
<A, X extends A, Y extends A, E2>(
filter: Predicate<X>,
orLeftWith: (a: Y) => E2
): <E>(self: Either<E, A>) => Either<E2 | E, A>
<E, A, B extends A, X extends A, E2>(
self: Either<E, A>,
filter: Refinement<A, B>,
orLeftWith: (a: X) => E2
): Either<E | E2, B>
<E, A, X extends A, Y extends A, E2>(
self: Either<E, A>,
filter: Predicate<X>,
orLeftWith: (a: Y) => E2
): Either<E | E2, A>
} = dual(3, <E, A, E2>(
self: Either<E, A>,
filter: Predicate<A>,
orLeftWith: (a: A) => E2
): Either<E | E2, A> => flatMap(self, (a) => filter(a) ? right(a) : left(orLeftWith(a))))

/**
* @category getters
* @since 2.0.0
Expand Down
6 changes: 6 additions & 0 deletions test/Either.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ describe.concurrent("Either", () => {
Util.deepStrictEqual(Either.flip(Either.left("b")), Either.right("b"))
})

it("filterOrLeft", () => {
Util.deepStrictEqual(Either.filterOrLeft(Either.right(1), (n) => n > 0, () => "a"), Either.right(1))
Util.deepStrictEqual(Either.filterOrLeft(Either.right(1), (n) => n > 1, () => "a"), Either.left("a"))
Util.deepStrictEqual(Either.filterOrLeft(Either.left(1), (n) => n > 0, () => "a"), Either.left(1))
})

it("merge", () => {
Util.deepStrictEqual(Either.merge(Either.right(1)), 1)
Util.deepStrictEqual(Either.merge(Either.left("a")), "a")
Expand Down

0 comments on commit 33ffa62

Please sign in to comment.