📦 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 -> element
import 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
📦 Like Maybe
, but able to know at type-level whether Empty
is a possibility
import Emptiable exposing (Emptiable, filled, fill)
[ filled 1, filled 7 ]
--: List (Emptiable number_ never_)
|> List.map fill
--> [ 1, 7 ]
Emptiable
by itself probably won't be that useful,
but it can make data structures type-safely non-emptiable:
import Emptiable exposing (map)
top : Emptiable (Stacked element) Never -> element
map Dict.NonEmpty.head
--: Emptiable (NonEmptyDict comparable v) possiblyOrNever
--: -> Emptiable ( comparable, v ) possiblyOrNever
Go take a look at all the data structures in this package
empty : Emptiable filling_ Possibly
Insert joke about life here
Emptiable.empty
|> Emptiable.map (\x -> x / 0)
--> Emptiable.empty
filled : fill -> Emptiable fill never_
Emptiable
that certainly exists, allowing type-safe extraction
import Emptiable exposing (filled, fill)
filled "Bami" |> fill
--> "Bami"
fromMaybe : Maybe value -> Emptiable value Possibly
Convert a Maybe
to an Emptiable
Possibly
To create new Emptiable
s, use filled
and empty
instead!
fuzz : Fuzzer fill -> Fuzzer (Emptiable fill Possibly)
Emptiable fill Possibly
Fuzzer
of a given fill
import Fuzz
Emptiable.fuzz Fuzz.char
|> Fuzz.examples 4
--> [ filled 'U', empty, filled 'M', empty ]
map : (fill -> mapped) -> Emptiable fill possiblyOrNever -> Emptiable mapped possiblyOrNever
If the Emptiable
is filled
, change it based on its current fill
:
import Emptiable exposing (filled, map)
filled -3 |> map abs
--> filled 3
Emptiable.empty |> map abs
--> Emptiable.empty
mapFlat : (fill -> Emptiable fillIfBothFilled possiblyOrNever) -> Emptiable fill possiblyOrNever -> Emptiable fillIfBothFilled possiblyOrNever
Chain together operations that may return empty
.
It's like calling map
|>
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, mapFlat)
emptiableString
|> mapFlat parse
|> mapFlat extraValidation
parse : ( Char, String ) -> Emptiable Parsed Possibly
extraValidation : Parsed -> Emptiable Parsed Possibly
For any number of arguments:
and
... |> ... |>
mapFlat
:
import Emptiable exposing (filled, mapFlat, and)
(filled 3)
|> and (filled 4)
|> and (filled 5)
|> mapFlat
(\( ( a, b ), c ) -> filled ( a, b, c ))
--> filled ( 3, 4, 5 )
and : Emptiable anotherFill possiblyOrNever -> Emptiable fill possiblyOrNever -> Emptiable ( fill, anotherFill ) possiblyOrNever
If the incoming food and the given argument are
filled
, give a filled
tuple of both fill
s back
If any is empty
, give a Emptiable.empty
back
and
comes in handy when multiple arguments need to be filled
import Emptiable exposing (filled, map, and)
filled 3
|> and (filled 4)
|> and (filled 5)
|> map (\( ( a0, a1 ), a2 ) -> a0^a1 - a2^2)
--> filled 56
flatten : Emptiable (Emptiable fill possiblyOrNever) possiblyOrNever -> Emptiable fill possiblyOrNever
In 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.empty
fill : Emptiable fill Basics.Never -> fill
Safely 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.first
fillElseOnEmpty : (possiblyOrNever -> fill) -> Emptiable fill possiblyOrNever -> fill
Lazily 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 =
fillElseOnEmpty
toMaybe : Emptiable fill possiblyOrNever_ -> Maybe fill
Convert to a Maybe
Don't try to use this prematurely. Keeping type information as long as possible is always a win
emptyAdapt : (possiblyOrNever -> adaptedPossiblyOrNever) -> Emptiable fill possiblyOrNever -> Emptiable fill adaptedPossiblyOrNever
Change the possiblyOrNever
type
Empty Possibly
An 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)
Never
The 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 never
makes both branches return possiblyOrNever