@algosail/maybe
v0.1.0
Published
The Maybe monad — safe handling of absent values without null checks or exceptions.
Readme
@algosail/maybe
The Maybe monad — safe handling of absent values without null checks or exceptions.
A Maybe<A> is either just(a) (a present value) or nothing() (absence).
Contents
- just
- nothing
- fromNullable
- fromPredicate
- tryCatch
- isJust / isNothing / isMaybe
- maybe
- maybe_
- fromMaybe
- fromMaybe_
- toNull / toUndefined
- justs
- map
- filter
- filterMap
- flatmap
- mapNullable
- mapMaybe
- ap
- alt
- exists
- fold
- maybeToEither
just
just :: a -> Maybe aWraps a value in Just.
just(1) // => { tag: 'just', value: 1 }
just(null) // => { tag: 'just', value: null } — null is a valid Just value
just([1, 2]) // => { tag: 'just', value: [1, 2] }nothing
nothing :: () -> Maybe neverCreates a Nothing — the absence of a value.
nothing() // => { tag: 'nothing' }fromNullable
fromNullable :: a -> Maybe (NonNullable a)Converts null or undefined to Nothing, any other value (including 0, '', false) to Just.
fromNullable(42) // => just(42)
fromNullable(0) // => just(0)
fromNullable('') // => just('')
fromNullable(null) // => nothing()
fromNullable(undefined) // => nothing()fromPredicate
fromPredicate :: (a -> Boolean) -> a -> Maybe aReturns Just(a) if the predicate holds, Nothing otherwise.
fromPredicate((x) => x > 0)(5) // => just(5)
fromPredicate((x) => x > 0)(-1) // => nothing()
fromPredicate(Array.isArray)([]) // => just([])
fromPredicate(Array.isArray)({}) // => nothing()tryCatch
tryCatch :: (() -> a) -> Maybe aWraps a thunk — Just on success, Nothing on any thrown error.
tryCatch(() => JSON.parse('{"a":1}')) // => just({ a: 1 })
tryCatch(() => JSON.parse('bad!')) // => nothing()
tryCatch(() => {
throw new Error()
}) // => nothing()isJust / isNothing / isMaybe
isJust :: unknown -> Boolean
isNothing :: unknown -> Boolean
isMaybe :: unknown -> BooleanType guards for narrowing.
isJust(just(1)) // => true
isJust(nothing()) // => false
isJust(42) // => false
isNothing(nothing()) // => true
isNothing(just(1)) // => false
isMaybe(just(1)) // => true
isMaybe(nothing()) // => true
isMaybe(42) // => falsemaybe
maybe :: b -> (a -> b) -> Maybe a -> bStrict case-fold — the default value is always evaluated.
maybe(0)((x) => x * 2)(just(5)) // => 10
maybe(0)((x) => x * 2)(nothing()) // => 0maybe_
maybe_ :: (() -> b) -> (a -> b) -> Maybe a -> bLazy case-fold — the default thunk is only called for Nothing.
maybe_(() => expensiveDefault())((x) => x)(nothing()) // default thunk called
maybe_(() => expensiveDefault())((x) => x)(just(1)) // thunk never calledfromMaybe
fromMaybe :: a -> Maybe a -> aExtracts the value or returns the strict default.
fromMaybe(0)(just(5)) // => 5
fromMaybe(0)(nothing()) // => 0
fromMaybe([])(nothing()) // => []fromMaybe_
fromMaybe_ :: (() -> a) -> Maybe a -> aExtracts the value or calls the lazy default thunk.
fromMaybe_(() => Date.now())(nothing()) // default evaluated lazily
fromMaybe_(() => Date.now())(just(0)) // => 0, thunk never calledtoNull / toUndefined
toNull :: Maybe a -> a | null
toUndefined :: Maybe a -> a | undefinedConverts back to a nullable value for interop with non-Maybe APIs.
toNull(just(1)) // => 1
toNull(nothing()) // => null
toUndefined(just(1)) // => 1
toUndefined(nothing()) // => undefinedjusts
justs :: Array (Maybe a) -> Array aDiscards Nothings and unwraps Justs from an array.
justs([just(1), nothing(), just(2), nothing()]) // => [1, 2]
justs([nothing(), nothing()]) // => []map
map :: (a -> b) -> Maybe a -> Maybe bApplies f to the value inside Just, passes Nothing through unchanged.
map((x) => x + 1)(just(4)) // => just(5)
map((x) => x + 1)(nothing()) // => nothing()
map((s) => s.length)(just('hello')) // => just(5)filter
filter :: (a -> Boolean) -> Maybe a -> Maybe aReturns Nothing if the predicate fails or the input is already Nothing.
filter((x) => x > 0)(just(5)) // => just(5)
filter((x) => x > 0)(just(-1)) // => nothing()
filter((x) => x > 0)(nothing()) // => nothing()filterMap
filterMap :: (a -> Maybe b) -> Maybe a -> Maybe bMap and filter in one step — applies fn only to Just, short-circuits Nothing.
filterMap((x) => (x > 0 ? just(x * 10) : nothing()))(just(3)) // => just(30)
filterMap((x) => (x > 0 ? just(x * 10) : nothing()))(just(-1)) // => nothing()
filterMap((x) => (x > 0 ? just(x * 10) : nothing()))(nothing()) // => nothing()flatmap
flatmap :: (a -> Maybe b) -> Maybe a -> Maybe bMonadic bind — chains Maybe-returning functions.
const safeHead = (arr) => (arr.length > 0 ? just(arr[0]) : nothing())
const safeSqrt = (x) => (x >= 0 ? just(Math.sqrt(x)) : nothing())
flatmap(safeSqrt)(just(9)) // => just(3)
flatmap(safeSqrt)(just(-1)) // => nothing()
flatmap(safeSqrt)(nothing()) // => nothing()mapNullable
mapNullable :: (a -> b | null | undefined) -> Maybe a -> Maybe bMaps with a nullable-returning function, converting null/undefined results to Nothing.
mapNullable((obj) => obj.name)(just({ name: 'Alice' })) // => just('Alice')
mapNullable((obj) => obj.name)(just({})) // => nothing()
mapNullable((obj) => obj.name)(nothing()) // => nothing()mapMaybe
mapMaybe :: (a -> Maybe b) -> Array a -> Array bMaps over an array, discarding Nothings. More expressive than filter + map.
mapMaybe((x) => (x > 0 ? just(x * 2) : nothing()))([1, -2, 3, -4]) // => [2, 6]
mapMaybe(fromNullable)([1, null, 2, undefined, 3]) // => [1, 2, 3]ap
ap :: Maybe (a -> b) -> Maybe a -> Maybe bApplies a Just-wrapped function to a Just-wrapped value.
ap(just((x) => x + 1))(just(4)) // => just(5)
ap(nothing())(just(4)) // => nothing()
ap(just((x) => x + 1))(nothing()) // => nothing()alt
alt :: Maybe a -> Maybe a -> Maybe aReturns the first Just, falling back to the second. Useful for providing alternatives.
alt(just(2))(just(1)) // => just(1) — first wins
alt(just(2))(nothing()) // => just(2) — fallback
alt(nothing())(nothing()) // => nothing()exists
exists :: (a -> Boolean) -> Maybe a -> BooleanReturns true only when the Maybe is Just and the predicate holds.
exists((x) => x > 0)(just(1)) // => true
exists((x) => x > 0)(just(-1)) // => false
exists((x) => x > 0)(nothing()) // => falsefold
fold :: ((b, a) -> b) -> b -> Maybe a -> bFolds a Maybe into an accumulator — returns initial for Nothing.
fold((acc, x) => acc + x, 0)(just(5)) // => 5
fold((acc, x) => acc + x, 0)(nothing()) // => 0maybeToEither
maybeToEither :: a -> Maybe b -> Either a bConverts to Either — Nothing becomes Left(def), Just(v) becomes Right(v).
maybeToEither('not found')(just(42)) // => right(42)
maybeToEither('not found')(nothing()) // => left('not found')