Result

type Result error value = Ok value | Err error

as Functor Either in Haskell

map : (a -> b) -> Result x a -> Result x b
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"

just as Haskell Monad Either

andThen : (a -> Result x b) -> Result x a -> Result x b

its definition:

andThen : (a -> Result e b) -> Result e a -> Result e b
andThen f r =
    case r of
      Ok v -> f v
      Err m -> Err m

it only continues 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 m = if m >= 1 && m <= 12 then Ok m else Err "months must be between 1 and 12"
                              
toMonth : String -> Result String Int
toMonth s = toInt s |> 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"

it is often best to create a custom type that explicitly represents the exact ways your computation may fail

map2 : (a -> b -> v) -> Result x a -> Result x b -> Result x v
apply a function to two results, if both results are Ok. if not, the first argument which is an Err will propagate through

map2 (+) (String.toInt "1") (String.toInt "2") == Ok 3
map2 (+) (String.toInt "1") (String.toInt "y") == Err "could't conv string 'y' to an Int"
map2 (+) (String.toInt "x") (String.toInt "y") == Err "could't conv string 'x' to an Int"

map3 map4 map5

withDefault : a -> Result x a -> a

Result.withDefault 0 (String.toInt "123") == 123
Result.withDefault 0 (String.toInt "abc") == 0

toMaybe : Result x a -> Maybe a

parseInt : String -> Result ParseError Int

fromMaybe : x -> Maybe a -> Result x a
to interact with some code that primarily uses Results

parseInt : String -> Maybe Int

resultParseInt : String -> Result String Int

mapError : (x -> y) -> Result x a -> Result y a
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"