Result
A Result
is the result of a computation that may fail. This is a great
way to manage errors in Gren.
A Result
is either Ok
meaning the computation succeeded, or it is an
Err
meaning that there was some failure.
Query
If the result is Ok
check if the contained value matches the provided value.
Result.hasValue 123 (Ok 123) == True
Result.hasValue 123 (Ok 5) == False
Result.hasValue 123 (Err "failed") == False
If the result is Ok
check if the contained value passes the provided test.
Result.checkValue isOdd (Ok 5) == True
Result.checkValue isOdd (Ok 12) == False
Result.checkValue isOdd (Err "failed") == False
Returns the first Ok
value in an Array
of Result
s.
Result.firstOk [ Ok 5, Err 0, Ok 10 ] == Just 5
Result.firstOk [ Err 0, Err 1 ] == Nothing
Convert an Array
of Result err ok
to Result (Array err) (Array ok)
. You'll only
receive an Ok
if there are no Err
values in the Array
.
Result.allOk [ Ok 5, Err 0, Ok 10 ] == Err [ 0 ]
Result.allOk [ Ok 0, Ok 1 ] == Ok [ 0, 1 ]
Mapping
Apply 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.
Chaining
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 msg
This 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.
This is similar to andThen but the callback is triggered when
the Result
is an Err
value. This gives you the option of dealing with errors
in a chain.
toInt "a"
|> onError (\_msg -> Ok 1) -- defaulting to first month of the year
|> andThen toValidMonth
Handling Errors
If the result is Ok
return the value, but if the result is an Err
then
return a given default value. The following examples try to parse integers.
Result.withDefault 0 (Ok 123) == 123
Result.withDefault 0 (Err "no") == 0
Same as withDefault but the default value is provided by a function. This lets you avoid computing the default value if it isn't necessary.
Convert to a simpler Maybe
if the actual error message is not needed or
you need to interact with some code that primarily uses maybes.
parseInt : String -> Result ParseError Int
maybeParseInt : String -> Maybe Int
maybeParseInt string =
toMaybe (parseInt string)
Convert from a simple Maybe
to interact with some code that primarily
uses Results
.
parseInt : String -> Maybe Int
resultParseInt : String -> Result String Int
resultParseInt string =
fromMaybe ("error parsing string: " ++ toString string) (parseInt string)
Transform an Err
value. For example, say the errors we get have too much
information:
parseInt : String -> Result ParseError Int
type alias ParseError =
{ message : String
, code : Int
, position : (Int,Int)
}
mapError .message (parseInt "123") == Ok 123
mapError .message (parseInt "abc") == Err "char 'a' is not a number"