Add Do notation for option

This commit is contained in:
Eric Rumsey 2025-05-27 16:31:00 -05:00
parent 52e00c3f38
commit 75368c8ef8

View File

@ -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({}))
}
}