Skip to content
This repository was archived by the owner on Feb 16, 2021. It is now read-only.

Commit 36904c1

Browse files
authored
add MonadError (#47)
1 parent 2967a8e commit 36904c1

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

src/Either.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { Foldable } from './Foldable'
88
import type { Applicative } from './Applicative'
99
import type { Traversable } from './Traversable'
1010
import type { Semigroup } from './Semigroup'
11+
import type { MonadError } from './MonadError'
1112

1213
import { HKT } from './HKT'
1314
import { unsafeCoerce } from './Unsafe'
@@ -126,6 +127,21 @@ export function traverse<F, L, A, B>(applicative: Applicative<F>, f: (a: A) => H
126127
return applicative.map(of, f(a.value0))
127128
}
128129

130+
export function getMonadError<E>(): MonadError<E, HKT<IsEither, E>> {
131+
return {
132+
of,
133+
map,
134+
ap,
135+
chain,
136+
throwError<A>(e: E): Either<E, A> {
137+
return left(e)
138+
},
139+
catchError<A>(ma: Either<E, A>, handler: (e: E) => Either<E, A>): Either<E, A> {
140+
return either(handler, right, ma)
141+
}
142+
}
143+
}
144+
129145
export function concat<L, R>(semigroup: Semigroup<R>): (fx: Either<L, R>, fy: Either<L, R>) => Either<L, R> {
130146
return function concat(fx, fy) {
131147
const x = prj(fx)

src/Maybe.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import type { Alternative } from './Alternative'
1111
import type { Extend } from './Extend'
1212
import type { Setoid } from './Setoid'
1313
import type { Traversable } from './Traversable'
14+
import type { MonadError } from './MonadError'
15+
1416
import { id } from './Identity'
1517

1618
class IsMaybe {}
@@ -121,6 +123,15 @@ export function traverse<F, A, B>(applicative: Applicative<F>, f: (a: A) => HKT<
121123
return applicative.map(of, f(a))
122124
}
123125

126+
export function throwError<A>(e: void): Maybe<A> { // eslint-disable-line no-unused-vars
127+
return Nothing
128+
}
129+
130+
export function catchError<A>(ma: Maybe<A>, handler: (e: void) => Maybe<A>): Maybe<A> {
131+
const a = prj(ma)
132+
return a == null ? handler() : ma
133+
}
134+
124135
export function getSetoid<A>(setoid: Setoid<A>): Setoid<Maybe<A>> {
125136
return {
126137
equals(fx, fy) {
@@ -185,12 +196,15 @@ if (false) { // eslint-disable-line
185196
alt,
186197
pempty,
187198
extend,
188-
traverse
199+
traverse,
200+
throwError,
201+
catchError
189202
}: Monad<IsMaybe> &
190203
Foldable<IsMaybe> &
191204
Alt<IsMaybe> &
192205
Plus<IsMaybe> &
193206
Alternative<IsMaybe> &
194207
Extend<IsMaybe> &
195-
Traversable<IsMaybe>)
208+
Traversable<IsMaybe> &
209+
MonadError<*, IsMaybe>)
196210
}

src/MonadError.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// @flow
2+
import type { Monad } from './Monad'
3+
import type { Maybe } from './Maybe'
4+
5+
import { HKT } from './HKT'
6+
import * as maybe from './Maybe'
7+
8+
// The `MonadError` type class represents those monads which support errors via
9+
// `throwError` and `catchError`.
10+
//
11+
// - `throwError e` throws the error `e`
12+
// - `catchError x f` calls the error handler `f` if an error is thrown during the
13+
// evaluation of `x`.
14+
//
15+
// An implementation is provided for `ErrorT`, and for other monad transformers
16+
// defined in this library.
17+
//
18+
// Laws:
19+
//
20+
// - Left zero: `throwError e >>= f = throwError e`
21+
// - Catch: `catchError (throwError e) f = f e`
22+
// - Pure: `catchError (pure a) f = pure a`
23+
//
24+
25+
export interface MonadError<E, M> extends Monad<M> {
26+
throwError<A>(e: E): HKT<M, A>,
27+
catchError<A>(ma: HKT<M, A>, handler: (e: E) => HKT<M, A>): HKT<M, A>
28+
}
29+
30+
// This function allows you to provide a predicate for selecting the
31+
// exceptions that you're interested in, and handle only those exceptons.
32+
// If the inner computation throws an exception, and the predicate returns
33+
// Nothing, then the whole computation will still fail with that exception.
34+
export function catchJust<E, M, A, B>(
35+
monadError: MonadError<E, M>,
36+
predicate: (e: E) => Maybe<B>,
37+
ma: HKT<M, A>,
38+
handler: (b: B) => HKT<M, A>
39+
): HKT<M, A> {
40+
return monadError.catchError(ma, e => {
41+
const b = maybe.prj(predicate(e))
42+
return b == null ? monadError.throwError(e) : handler(b)
43+
})
44+
}

0 commit comments

Comments
 (0)