📦 A Maybe value that can be made non-empty depending on what we know – an "emptiable-able" value
import Stack exposing (Stacked)
fill : Emptiable fill Never -> fill
top : Emptiable (Stacked element) Never -> elementimport Emptiable exposing (Emptiable)
import Stack exposing (Stacked)
type alias Model =
WithoutConstructorFunction
{ searchKeyWords : Emptiable (Stacked String) Never
}where RecordWithoutConstructorFunction
stops the compiler from creating a constructor function for Model.
Insert joke about life here.
Emptiable.empty
|> Emptiable.fillMap (\x -> x / 0)
--> Emptiable.emptyEmptiable that certainly exists, allowing type-safe extraction.
import Emptiable exposing (filled, fill)
filled "Bami" |> fill
--> "Bami"Chain together operations that may return empty.
It's like calling fillMap|>flatten:
If the argument is Never empty,
a given function takes its fill
and returns a new possibly empty value.
Some call it
andThen
or flatMap.
import Emptiable exposing (Emptiable, fillMapFlat)
emptiableString
|> fillMapFlat parse
|> fillMapFlat extraValidation
parse : ( Char, String ) -> Emptiable Parsed Possibly
extraValidation : Parsed -> Emptiable Parsed PossiblyFor any number of arguments:
fillAnd... |> ... |>fillMapFlat:
import Emptiable exposing (filled, fillMapFlat, fillAnd)
(filled 3)
|> fillAnd (filled 4)
|> fillAnd (filled 5)
|> fillMapFlat
(\( ( a, b ), c ) -> filled ( a, b, c ))
--> filled ( 3, 4, 5 )If the incoming food and the given argument are
filled, give a filled tuple of both fills back.
If any is empty, give a Emptiable.empty back.
fillAnd comes in handy when multiple arguments need to be filled:
import Emptiable exposing (filled, fillMap, fillAnd)
filled 3
|> fillAnd (filled 4)
|> fillAnd (filled 5)
|> fillMap (\( ( a0, a1 ), a2 ) -> a0^a1 - a2^2)
--> filled 56In a nestable Emptiable:
Only keep it filled if the inner Emptiable is filled.
Some call it join.
import Emptiable exposing (filled)
filled (filled 1) |> Emptiable.flatten
--> filled 1
filled Emptiable.empty |> Emptiable.flatten
--> Emptiable.empty
Emptiable.empty |> Emptiable.flatten
--> Emptiable.emptySafely extract the filled content from a Emptiable fill Never.
import Emptiable exposing (filled)
filled (filled (filled "Bami"))
|> Emptiable.fill
|> Emptiable.fill
|> Emptiable.fill
--> "Bami"
first : Empty ( first, others_ ) Never -> first
first =
Emptiable.fill >> Tuple.firstLazily use a fallback value if the Emptiable is empty.
import Possibly exposing (Possibly(..))
import Emptiable exposing (Emptiable(..), fillElseOnEmpty)
import Dict
Dict.empty
|> Dict.get "Hannah"
|> Emptiable.fromMaybe
|> fillElseOnEmpty (\_ -> "unknown")
--> "unknown"
fill =
fillElseOnEmpty never
fatten =
fillElseOnEmptyConvert to a Maybe.
Don't try to use this prematurely. Keeping type information as long as possible is always a win.
Change the possiblyOrNever type.
Empty PossiblyAn Empty possiblyOrNever can't be used as Empty Possibly
import Emptiable
import Possibly exposing (Possibly)
import Stack exposing (Stacked)
type alias Log =
Empty Possibly (Stacked String)
fromStack : Emptiable (Stacked String) possiblyOrNever_ -> Log
fromStack stackFilled =
stackFilled
--: `possiblyOrNever_` but we need `Possibly`
|> Emptiable.emptyAdapt (always Possible)NeverThe Never can't be unified with Possibly or a type variable
import Emptiable
import Stack exposing (Stacked)
theShorter :
Emptiable (Stacked element) Never
-> Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever
theShorter aStack bStack =
if Stack.length bStack > Stack.length aStack then
bStack
else
aStack
--: `Never` but we need `possiblyOrNever`
|> Emptiable.emptyAdapt nevermakes both branches return possiblyOrNever.
📦 Like
Maybe, but able to know at type-level whetherEmptyis a possibility.Emptiableby itself probably won't be that useful, but it can make data structures type-safely non-emptiable:Go take a look at all the data structures in this package.