Skip to content

Instantly share code, notes, and snippets.

@briancavalier
Last active September 7, 2017 15:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save briancavalier/059b383bf417ecea0de79509eaec1ead to your computer and use it in GitHub Desktop.
Save briancavalier/059b383bf417ecea0de79509eaec1ead to your computer and use it in GitHub Desktop.
A simple Either with added exception semantics, like Haskell ExceptT
// @flow
import { curry2, curry3 } from '@most/prelude'
export type Except<E, A> = Exception<E, A> | Result<E, A>
export const result = <E, A> (a: A): Except<E, A> =>
new Result(a)
export const throwError = <E, A> (e: E): Except<E, A> =>
new Exception(e)
export const catchError = curry2(<E, F, A> (f: (E) => Except<F, A>, ex: Except<E, A>): Except<F, A> =>
ex.fold(f, result))
export const andFinally = curry2(<E, A, B> (f: () => B, ex: Except<E, A>): Except<E, A> =>
ex.fold(returnInstead(ex, f), returnInstead(ex, f)))
const returnInstead = <A, B, C> (b: B, f: () => C): ((A) => B) =>
(a) => (f(), b)
export const attempt0 = <E, Z> (f: () => Z): Except<E, Z> => {
try {
return result(f())
} catch (e) {
return throwError(e)
}
}
export const attempt1 = curry2(<E, A, Z> (f: (A) => Z, a: A): Except<E, Z> => {
try {
return result(f(a))
} catch (e) {
return throwError(e)
}
})
export const attempt2 = curry3(<E, A, B, Z> (f: (A, B) => Z, a: A, b: B): Except<E, Z> => {
try {
return result(f(a, b))
} catch (e) {
return throwError(e)
}
})
export const trace = <E: Error, A> (ex: Except<E, A>): ?string =>
ex.fold(getStack, noStack)
const getStack = e => e.stack
const noStack = _ => undefined
class Exception<E, A> {
error: E
constructor (error: E) {
this.error = error
}
static of (a: A): Except<E, A> {
return new Result(a)
}
fold <B> (f: (E) => B, _: (A) => B): B {
return f(this.error)
}
chain <B> (_: (A) => Except<E, B>): Except<E, B> {
return new Exception(this.error)
}
ap <E, B> (_: Except<E, (A) => B>): Except<E, B> {
return new Exception(this.error)
}
map <B> (_: (A) => B): Except<E, B> {
return new Exception(this.error)
}
bimap <F, B> (f: (E) => F, _: (A) => B): Except<F, B> {
return new Exception(f(this.error))
}
alt (ex: Except<E, A>): Except<E, A> {
return ex
}
}
class Result<E, A> {
value: A
constructor (value: A) {
this.value = value
}
static of (a: A): Except<E, A> {
return new Result(a)
}
fold <B> (_: (E) => B, g: (A) => B): B {
return g(this.value)
}
chain <B> (f: (A) => Except<E, B>): Except<E, B> {
return f(this.value)
}
ap <E, B> (ex: Except<E, (A) => B>): Except<E, B> {
return ex.fold(throwError, f => new Result(f(this.value)))
}
map <B> (f: (A) => B): Except<E, B> {
return new Result(f(this.value))
}
bimap <F, B> (_: (E) => F, g: (A) => B): Except<F, B> {
return new Result(g(this.value))
}
alt (_: Except<E, A>): Except<E, A> {
return this
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment