d5693e2cdf
Added promoting warnings to errors |
||
---|---|---|
src/Control/Monad | ||
test | ||
.travis.yml | ||
ChangeLog.md | ||
LICENSE | ||
README.md | ||
Setup.hs | ||
stack.yaml | ||
validationt.cabal |
ValidationT
A very small validation data library.
Usage
Suppose you want to validate some data from the user. Say, that the password adheres to some rules.
You might do something like this:
validatePassword :: Monad m => String -> ValidationT [String] m ()
validatePassword password = do
vLength password
vAlpha password
vNum password
where
vLength p = when (length p < 8)
$ vWarning ["The password should be at least 8 characters long."]
vAlpha p = unless (any isAlpha p)
$ vWarning ["The password should contain at least one alphabetic character."]
vNum p = unless (any isDigit p)
$ vWarning ["The password should contain at least one numeric character."]
ValidationT e m a
essentially just gathers the errors thrown by vWarning
.
vWarning :: (Monad m, Monoid e) => e -> ValidationT e m ()
vWarning
mappend
s the given e
to the already collected errors. This is why the warnings are contained inside a list.
There is also vError
. The only difference between vWarning
and vError
is that vError
stops further execution (and further collection of errors and warnings).
You would use the validation like this:
main :: IO ()
main = do
password <- getLine
result <- runValidationTEither . validatePassword $ password
putStrLn $ case result of
Left errs -> unlines err
Right () -> "You are fine."
You could, of course, do more complicated things like use vWarningL
and vErrorL
to add an error to a mempty
structure, which gets mappend
ed with other errors.
The library comes with a MonoidMap
newtype
wrapper around Map
, which mappend
s the values themselves on conflict. This can be useful if you have a multiple points of failure and you want to distinguich between them -- validating a username and a password for example:
data Piece
= Password
| UserName
deriving (Eq, Show, Ord)
validatePassword :: Monad m => String -> ValidationT (MonoidMap Piece [String]) m ()
validatePassword password = do
vLength password
vAlpha password
vNum password
where
warning = mmSingleton UserName
vLength p = when (length p < 8)
$ warning ["The password should be at least 8 characters long."]
vAlpha p = unless (any isAlpha p)
$ warning ["The password should contain at least one alphabetic character."]
vNum p = unless (any isDigit p)
$ warning ["The password should contain at least one numeric character."]
(mmSingleton
is a covenience initializer for MonoidMap
.)