Compare commits
3 Commits
83a0c1cf31
...
e696e5d9d2
| Author | SHA1 | Date | |
|---|---|---|---|
| e696e5d9d2 | |||
| 75368c8ef8 | |||
| 52e00c3f38 |
@ -14,15 +14,55 @@ export const right = <A>(a: A): Either<A, never> => ({
|
|||||||
|
|
||||||
// Operations
|
// Operations
|
||||||
export const eitherMap =
|
export const eitherMap =
|
||||||
<E, A, B>(f: (a: A) => B) => (fa: Either<A, E>): Either<B, E> =>
|
<A, B, E>(f: (a: A) => B) => (fa: Either<A, E>): Either<B, E> =>
|
||||||
fa._tag === 'Right' ? right(f(fa.right)) : fa
|
fa._tag === 'Right' ? right(f(fa.right)) : fa
|
||||||
|
|
||||||
export const eitherChain =
|
export const eitherChain =
|
||||||
<E, A, B>(f: (a: A) => Either<B, E>) =>
|
<A, B, E>(f: (a: A) => Either<B, E>) => (fa: Either<A, E>): Either<B, E> =>
|
||||||
(fa: Either<A, E>): Either<B, E> =>
|
|
||||||
fa._tag === 'Right' ? f(fa.right) : fa
|
fa._tag === 'Right' ? f(fa.right) : fa
|
||||||
|
|
||||||
export const fold =
|
export const fold =
|
||||||
<A, B, E>(onLeft: (e: E) => B, onRight: (a: A) => B) =>
|
<A, B, E>(onLeft: (e: E) => B, onRight: (a: A) => B) =>
|
||||||
(fa: Either<A, E>): B =>
|
(fa: Either<A, E>): B =>
|
||||||
fa._tag === 'Left' ? onLeft(fa.left) : onRight(fa.right)
|
fa._tag === 'Left' ? onLeft(fa.left) : onRight(fa.right)
|
||||||
|
|
||||||
|
// Do notation
|
||||||
|
export class DoEither<T extends Record<string, unknown>, E> {
|
||||||
|
constructor(private readonly either: Either<T, E>) {}
|
||||||
|
|
||||||
|
bind<K extends string, A>(
|
||||||
|
key: K,
|
||||||
|
fa: Either<A, E>,
|
||||||
|
): DoEither<T & Record<K, A>, E> {
|
||||||
|
const newEither = eitherChain<T, T & Record<K, A>, E>((scope: T) =>
|
||||||
|
eitherMap<A, T & Record<K, A>, E>((a: A) => ({...scope, [key]: a}))(fa)
|
||||||
|
)(this.either)
|
||||||
|
return new DoEither(newEither)
|
||||||
|
}
|
||||||
|
|
||||||
|
return<B>(f: (scope: T) => B): Either<B, E> {
|
||||||
|
return eitherMap<T, B, E>(f)(this.either)
|
||||||
|
}
|
||||||
|
|
||||||
|
done(): Either<T, E> {
|
||||||
|
return this.either
|
||||||
|
}
|
||||||
|
|
||||||
|
do(fa: Either<unknown, E>): DoEither<T, E> {
|
||||||
|
const newEither = eitherChain<T, T, E>((scope: T) =>
|
||||||
|
eitherMap<unknown, T, E>(() => scope)(fa)
|
||||||
|
)(this.either)
|
||||||
|
return new DoEither(newEither)
|
||||||
|
}
|
||||||
|
|
||||||
|
doL(f: (scope: T) => Either<unknown, E>): DoEither<T, E> {
|
||||||
|
const newEither = eitherChain<T, T, E>((scope: T) =>
|
||||||
|
eitherMap<unknown, T, E>(() => scope)(f(scope))
|
||||||
|
)(this.either)
|
||||||
|
return new DoEither(newEither)
|
||||||
|
}
|
||||||
|
|
||||||
|
static start<E>(): DoEither<{}, E> {
|
||||||
|
return new DoEither(right({}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -10,9 +10,8 @@ export const some = <A>(value: A): Option<A> => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Operations
|
// Operations
|
||||||
export const map =
|
export const map = <A, B>(f: (a: A) => B) => (fa: Option<A>): Option<B> =>
|
||||||
<A, B>(f: (a: A) => B) => (fa: Option<A>): Option<B> =>
|
fa._tag === 'Some' ? some(f(fa.value)) : none
|
||||||
fa._tag === 'Some' ? some(f(fa.value)) : none
|
|
||||||
|
|
||||||
export const chain =
|
export const chain =
|
||||||
<A, B>(f: (a: A) => Option<B>) => (fa: Option<A>): Option<B> =>
|
<A, B>(f: (a: A) => Option<B>) => (fa: Option<A>): Option<B> =>
|
||||||
@ -20,3 +19,37 @@ export const chain =
|
|||||||
|
|
||||||
export const getOrElse = <A>(defaultValue: A) => (fa: Option<A>): A =>
|
export const getOrElse = <A>(defaultValue: A) => (fa: Option<A>): A =>
|
||||||
fa._tag === 'Some' ? fa.value : defaultValue
|
fa._tag === 'Some' ? fa.value : defaultValue
|
||||||
|
|
||||||
|
export class DoOption<T extends Record<string, unknown>> {
|
||||||
|
constructor(private readonly option: Option<T>) {}
|
||||||
|
|
||||||
|
bind<K extends string, A>(key: K, fa: Option<A>): DoOption<T & Record<K, A>> {
|
||||||
|
const newOption = chain((scope: T) =>
|
||||||
|
map((a: A) => ({...scope, [key]: a}))(fa)
|
||||||
|
)(this.option)
|
||||||
|
return new DoOption(newOption as Option<T & Record<K, A>>)
|
||||||
|
}
|
||||||
|
|
||||||
|
return<B>(f: (scope: T) => B): Option<B> {
|
||||||
|
return map(f)(this.option)
|
||||||
|
}
|
||||||
|
|
||||||
|
done(): Option<T> {
|
||||||
|
return this.option
|
||||||
|
}
|
||||||
|
do(fa: Option<unknown>): DoOption<T> {
|
||||||
|
const newOption = chain((scope: T) => map(() => scope)(fa))(this.option)
|
||||||
|
return new DoOption(newOption)
|
||||||
|
}
|
||||||
|
|
||||||
|
doL(f: (scope: T) => Option<unknown>): DoOption<T> {
|
||||||
|
const newOption = chain((scope: T) => map(() => scope)(f(scope)))(
|
||||||
|
this.option,
|
||||||
|
)
|
||||||
|
return new DoOption(newOption)
|
||||||
|
}
|
||||||
|
|
||||||
|
static start(): DoOption<{}> {
|
||||||
|
return new DoOption(some({}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,14 +2,11 @@ import { type Either, left, right } from './either'
|
|||||||
import { none, type Option, some } from './option'
|
import { none, type Option, some } from './option'
|
||||||
|
|
||||||
// Pipe function for composition
|
// Pipe function for composition
|
||||||
export const pipe = <A, B, C>(
|
export const pipe = <A, B, C>(a: A, ab: (a: A) => B, bc: (b: B) => C): C =>
|
||||||
a: A,
|
bc(ab(a))
|
||||||
ab: (a: A) => B,
|
|
||||||
bc: (b: B) => C,
|
|
||||||
): C => bc(ab(a))
|
|
||||||
|
|
||||||
// TryCatch helper using Either
|
// TryCatch helper using Either
|
||||||
export const tryCatch = <A>(f: () => A): Either<Error, A> => {
|
export const tryCatch = <A>(f: () => A): Either<A, Error> => {
|
||||||
try {
|
try {
|
||||||
return right(f())
|
return right(f())
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user