An extended toolbox for working with results: everything from the elm/core
Result module plus Haskell-inspired helpers such as fromOk, isOk and
toList, all implemented the Elm way.
Provide a default value, turning an optional value into a normal
value.
Alias of withDefault.
Return True iff its argument is of the form Ok _.
Basic usage:
isOk (Ok 3) == True
isOk (Ok ()) == True
isOk (Err "error") == FalseOnly the outer constructor is taken into consideration:
isOk (Ok (Err "err")) == TrueReturn True iff its argument is Err _.
Basic usage:
isErr (Ok 3) == False
isErr (Ok ()) == False
isErr (Err ()) == TrueOnly the outer constructor is taken into consideration:
isErr (Ok (Err "err")) == FalseApply a function to a result. If the result is Ok, it will be converted.
If the result is an Err, the same error value will propagate through.
map sqrt (Ok 4.0) == Ok 2.0
map sqrt (Err "bad input") == Err "bad input"Apply a function if both results are Ok. If not, the first Err will
propagate through.
map2 max (Ok 42) (Ok 13) == Ok 42
map2 max (Err "x") (Ok 13) == Err "x"
map2 max (Ok 42) (Err "y") == Err "y"
map2 max (Err "x") (Err "y") == Err "x"This can be useful if you have two computations that may fail, and you want to put them together quickly.
Convert to Maybe::Just if given argument is Ok _ and
Nothing otherwise.
Convert to Maybe::Just if given argument is Err _ and
Nothing otherwise.
Return the contents of Ok value or a default value otherwise.
Return the contents of Err value or a default value otherwise.
Return an empty list when given Err _ or a singleton list when
given Ok _.
Basic usage:
toList (Ok 7) == [ 7 ]
toList (Err _) == []One can use maybeToList to avoid pattern matching when combined with a function that (safely) works on lists:
(sum <|
toList <|
fromMaybe "parse error" <|
String.toInt "3"
)
== 3
(sum <|
toList <|
fromMaybe "parse error" <|
String.toInt ""
)
== 0Take a list of Results and return a list of all the Ok values.
Basic usage:
catOks [ Ok 1, Err (), Ok 3 ] == [ 1, 3 ]When constructing a list of Result values, catOks can be used to return all of the "success" results (if the list is the result of a map, then mapMaybe would be more appropriate):
type ParseError = ParseError String
toInt s = String.toInt s |> fromMaybe (ParseError s)
catOks (map toInt [ "1", "Foo", "3" ]) == [ 1, 3 ]Take a list of Results and return a list of all the Err values.
Basic usage:
catErrs [ Err 1, Ok (), Err 3 ] == [ 1, 3 ]When constructing a list of Result values, catErrs can be used to return all of the "failure" results (if the list is the result of a map, then mapMaybe would be more appropriate):
type ParseError = ParseError String
toInt s = String.toInt s |> fromMaybe (ParseError s)
catOks (map toInt [ "1", "Foo", "3" ]) == [ 1, 3 ]Partition a list of Result into two lists. All the Err elements are
extracted, in order, to the first component of the output. Similarly the
Ok elements are extracted to the second component of the output.
Basic usage:
let list = [ Err "foo", Ok 3, Err "bar", Ok 7, Err "baz" ]
partition list == (["foo","bar","baz"],[3,7])The pair returned by partitionEithers x should be the same pair as (lefts x, rights x):
let list = [ Err "foo", Ok 3, Err "bar", Ok 7, Err "baz" ]
partition list == (errs list, oks list) == TrueApply the first function to the given value inside Err or the second
function to the value inside Ok.
fold (\e -> "Error: " ++ e) String.toUpper (Ok "elm") == "ELM"
fold (\e -> "Error: " ++ e) String.toUpper (Err "fail") == "Error: fail"Chain together a sequence of computations that may fail. It is helpful to see its definition:
andThen : (a -> Result e b) -> Result e a -> Result e b
andThen callback result =
case result of
Ok value ->
callback value
Err msg ->
Err msgThis means we only continue with the callback if things are going well. For
example, say you need to use (toInt : String -> Result String Int) to parse
a month and make sure it is between 1 and 12:
toValidMonth : Int -> Result String Int
toValidMonth month =
if month >= 1 && month <= 12 then
Ok month
else
Err "months must be between 1 and 12"
toMonth : String -> Result String Int
toMonth rawString =
toInt rawString
|> andThen toValidMonth
-- toMonth "4" == Ok 4
-- toMonth "9" == Ok 9
-- toMonth "a" == Err "cannot parse to an Int"
-- toMonth "0" == Err "months must be between 1 and 12"This allows us to come out of a chain of operations with quite a specific error message. It is often best to create a custom type that explicitly represents the exact ways your computation may fail. This way it is easy to handle in your code.
Return second argument if first argument is Ok, otherwise first.
and (Ok 2) (Err "late error") == Err "late error"
and (Err "early error") (Ok "foo") == Err "early error"
and (Err "not a 2") (Err "late error") == Err "not a 2"
and (Ok 2) (Ok "different type") == Ok "different type"Return first argument if it is Ok, otherwise second.
or (Ok 2) (Err "late error") == Ok 2
or (Err "early error") (Ok 2) == Ok 2
or (Err "not a 2") (Err "late error") == Err "late error"
or (Ok 2) (Ok 100) == Ok 2Apply given function within Ok to the second argument if it is Ok,
pass throught Err otherwise.
Provide a default value, turning an optional value into a normal value. This comes in handy when paired with functions like
Dict.getwhich gives back aMaybe.Note: This can be overused! Many cases are better handled by a
caseexpression. And if you end up usingwithDefaulta lot, it can be a good sign that a custom type will clean your code up quite a bit!