both or only one of them
AndOrThe basic types of this package look like this:
type AndOr first second
= Both ( first, second )
| Only (Or first second)
type Or first second
= First first
| Second secondBoth types can be quite useful! ...But first
AndOr and Or are prone to misuse, just like Maybe, tuple, Bool etc.
When there is a representation of your data that's more descriptive, use that instead!
Example: Modeling the result of an operation that can fail, succeed or succeed with warnings
type alias Fallible a =
AndOr a ErrorThis is problematic from multiple standpoints:
type alias Fallible a =
Or { result : a, warnings : List RecoverableError }
UnrecoverableErrortype Fallible a
= Success { result : a, errors : List RecoverableError }
| UnrecoverableError UnrecoverableErrorAndOr and Or are useful for generic operations where no descriptive names exist –
similar to how tuples are used for partition results because there is no information
on what each side means.
KeysSet.fold2From which is similar to Dict.merge but more comprehensible and easier to work with thanks to AndOrList.AndOr.map2 : (AndOr a b -> c) -> ( List a, List b ) -> List c
List.AndOr.map2 combine lists =
case lists of
( firsts, [] ) ->
firsts
|> List.map
(\first -> Only (Or.First first) |> combine)
( [], seconds ) ->
seconds
|> List.map
(\first -> Only (Or.Second first) |> combine)
( firstHead :: firstTail, secondHead :: secondTail ) ->
(AndOr.Both firstHead secondHead |> combine)
:: List.AndOr.map2 combine firstTail secondTailList.Or.partition : (a -> Or first second) -> (List a -> ( List first, List second ))
List.Or.partition chooseSide list =
case list of
[] ->
[]
head :: tail ->
let
consHead : ( List first, List second ) -> ( List first, List second )
consHead =
case head |> chooseSide of
First first ->
And.firstMap ((::) first)
Second second ->
And.secondMap ((::) second)
in
tail |> List.Or.partition chooseSide |> consHeadAndOrAll of them don't separate out the "only one of both" case.
Orkingwither/elmeithertoastal/eithervoidLeft for setting, singleton for Right etc.Data.EitherAll of them use Left and Right as variant names whereas Or's First and Second are consistent with elm's tuple part names.
The API is pretty slim, only covering the needs I could think of. If you have an idea for a useful helper → contribute