A Validation represents either success or failure.
fromResult (Ok 5) == succeed 5
fromResult (Err "x") == fail "x"fromMaybe "x" (Just 5) == succeed 5
fromMaybe "x" Nothing == fail "x"isValid (succeed 5) == True
isValid (fail "x") == FalseisInvalid (succeed 5) == False
isInvalid (fail "x") == TrueApply a function to a validation. If the validation is a success, the value will be converted. If the validation is a failure, the same error will be propagated.
map sqrt (succeed 4.0) == succeed 2.0
map sqrt (fail "bad input") == fail "bad input"Apply a function if both validations are a success. If not, the errors will be accumulated in order of failure.
map2 max (succeed 42) (succeed 13) == succeed 42
map2 max (fail "x") (succeed 13) == fail "x"
map2 max (succeed 42) (fail "y") == fail "y"
map2 max (fail "x") (fail "y") == failWithErrors "x" [ "y" ]Apply a function if all three validations are a success. If not, the errors will be accumulated in order of failure.
map3 (\a b c -> a + b + c) (succeed 1) (succeed 2) (succeed 3) == succeed 6
map3 (\a b c -> a + b + c) (succeed 1) (fail "y") (succeed 3) == fail "y"
map3 (\a b c -> a + b + c) (fail "x") (succeed 2) (fail "z") == failWithErrors "x" [ "z" ]
map3 (\a b c -> a + b + c) (fail "x") (fail "y") (fail "z") == failWithErrors "x" [ "y", "z" ]Adds support for an applicative style of programming.
Practically, it means that when you need to go beyond map5 you can use this function together with succeed to achieve it. For e.g.
succeed (\a b c d e f g h i j k -> ...)
|> apply va
|> apply vb
|> apply vc
|> apply vd
|> apply ve
|> apply vf
|> apply vg
|> apply vh
|> apply vi
|> apply vj
|> apply vkChain together a sequence of validations that may fail.
We only continue with the callback if things are going well.
toInt : String -> Validation String Int
toInt rawString =
fromMaybe "cannot convert to an Int" (String.toInt rawString)
toMonthFromInt : Int -> Validation String Int
toMonthFromInt anyInt =
if anyInt >= 1 && anyInt <= 12 then
succeed anyInt
else
fail "months must be between 1 and 12"
toMonthFromString : String -> Validation String Int
toMonthFromString rawString =
toInt rawString
|> andThen toMonthFromInt
-- toMonthFromString "4" == succeed 4
-- toMonthFromString "9" == succeed 9
-- toMonthFromString "a" == fail "cannot convert to an Int"
-- toMonthFromString "0" == fail "months must be between 1 and 12"withDefault 0 (succeed 5) == 5
withDefault 0 (fail "x") == 0toResult (succeed 5) == Ok 5
toResult (fail "x") == Err [ "x" ]
toResult (failWithErrors "x" [ "y" ]) == Err [ "x", "y" ]toMaybe (succeed 5) == Just 5
toMaybe (fail "x") == Nothing
toMaybe (failWithErrors "x" [ "y" ]) == NothingfirstError (succeed 5) == Nothing
firstError (fail "x") == Just "x"
firstError (failWithErrors "x" [ "y", "z" ]) == Just "x"lastError (succeed 5) == Nothing
lastError (fail "x") == Just "x"
lastError (failWithErrors "x" [ "y", "z" ]) == Just "z"allErrors (succeed 5) == []
allErrors (fail "x") == [ "x" ]
allErrors (failWithErrors "x" [ "y", "z" ]) == [ "x", "y", "z" ]
It can fail with one or more errors. The major difference between
ValidationandResultis that when validations are composed their errors accumulate.