export type None = {readonly _tag: 'None'}
export type Some = {readonly _tag: 'Some', readonly value: A}
export type Option = Some | None
// Constructors
export const none: Option = {_tag: 'None'}
export const some = (value: A): Option => ({
_tag: 'Some',
value,
})
// Operations
export const map = (f: (a: A) => B) => (fa: Option): Option =>
fa._tag === 'Some' ? some(f(fa.value)) : none
export const chain =
(f: (a: A) => Option) => (fa: Option): Option =>
fa._tag === 'Some' ? f(fa.value) : none
export const getOrElse = (defaultValue: A) => (fa: Option): A =>
fa._tag === 'Some' ? fa.value : defaultValue
export class DoOption> {
constructor(private readonly option: Option) {}
bind(key: K, fa: Option): DoOption> {
const newOption = chain((scope: T) =>
map((a: A) => ({...scope, [key]: a}))(fa)
)(this.option)
return new DoOption(newOption as Option>)
}
return(f: (scope: T) => B): Option {
return map(f)(this.option)
}
done(): Option {
return this.option
}
do(fa: Option): DoOption {
const newOption = chain((scope: T) => map(() => scope)(fa))(this.option)
return new DoOption(newOption)
}
doL(f: (scope: T) => Option): DoOption {
const newOption = chain((scope: T) => map(() => scope)(f(scope)))(
this.option,
)
return new DoOption(newOption)
}
static start(): DoOption<{}> {
return new DoOption(some({}))
}
}