export type Nothing = { kind: 'Nothing'; }; export type Just = { kind: 'Just'; value: A; }; export type Maybe = Just | Nothing; /* Create a Maybe with an actual value */ export function Just(value: A): Maybe { return { kind: 'Just', value: value, }; } /* Create a Maybe with no value */ export function Nothing(): Maybe { return { kind: 'Nothing', }; } export function isJust(maybe: Maybe): maybe is Just { switch (maybe.kind) { case 'Just': return true; default: return false; } } export function isNothing(maybe: Maybe): maybe is Just { switch (maybe.kind) { case 'Nothing': return true; default: return false; } } /* If a maybe has a value, return it. Otherwise return the provided value */ export function withDefault(value: A, maybeValue: Maybe): A { switch (maybeValue.kind) { case 'Just': return maybeValue.value; default: return value; } } /* If a maybe has a value, apply a function to it and return a maybe containing the new value. Otherwise return Nothing. */ export function map( func: (val: A) => Value, maybeValue: Maybe ): Maybe { switch (maybeValue.kind) { case 'Just': return Just(func(maybeValue.value)); default: return maybeValue; } } /* If both maybes have a value, apply a function to them and return a maybe containing the new value. Otherwise return Nothing. */ export function map2( func: (firstValue: A, secondValue: B) => Value, firstMaybeValue: Maybe, secondMaybeValue: Maybe ): Maybe { switch (firstMaybeValue.kind) { case 'Just': switch (secondMaybeValue.kind) { case 'Just': return Just( func(firstMaybeValue.value, secondMaybeValue.value) ); default: return Nothing(); } default: return Nothing(); } } /* If all maybes have a value, apply a function to them and return a maybe containing the new value. Otherwise return Nothing. */ export function map3( func: (firstValue: A, secondValue: B, thirdValue: C) => Value, firstMaybeValue: Maybe, secondMaybeValue: Maybe, thirdMaybeValue: Maybe ): Maybe { switch (firstMaybeValue.kind) { case 'Just': switch (secondMaybeValue.kind) { case 'Just': switch (thirdMaybeValue.kind) { case 'Just': return Just( func( firstMaybeValue.value, secondMaybeValue.value, thirdMaybeValue.value ) ); default: return Nothing(); } default: return Nothing(); } default: return Nothing(); } } /* If the maybe has a value, apply a function that turns things into a maybe to it. Otherwise return Nothing. */ export function andThen( func: (firstValue: A) => Maybe, maybeValue: Maybe ): Maybe { switch (maybeValue.kind) { case 'Just': return func(maybeValue.value); default: return Nothing(); } }