úÎB¦@(     © 2018 Luka Had~iegriMIT#Luka Had~iegri <reygoch@gmail.com> experimentalportableSafeFTV?:Internal datatype used for handling users error structure.\Tag used with type family to tell the compiler that we are constructing the "error" record.?A simple type family used for constructing your data structure.TNow that we have defined our input and error data types we can start constructing a N for our data. In essence validator is just a function that takes in an input i and returns an error e wrapped in a monad m if your input was invalid. is an 5 and you can construct a new one by using functions:  ,  ,  ,  ,  ,  and k. Those functions have to be provided with actual checks to perform, and we define a single check by using <, so let's create some simple checks to perform on our data: ÿ&over18 :: Monad m => Int -> ExceptT String m Int over18 n | n < 18 = throwE "must be over 18" | otherwise = pure n nonempty :: Monad m => String -> ExceptT [String] m String nonempty s | length s == 0 = throwE ["can't be empty"] | otherwise = pure s nonbollocks :: Monad m => String -> ExceptT [String] m String nonbollocks s | s == "bollocks" = throwE ["can't be bollocks"] | otherwise = pure s nonshort :: Monad m => String -> ExceptT [String] m String nonshort s = if length s < 10 then throwE ["too short"] else pure s With this we can finally create  s for our User and Article data types: ÿÃarticleValidator :: Monad m => Validator Article m ArticleError articleValidator = Article <$> check id over18 <*> checks title [nonempty, nonbollocks] <*> checks content [nonempty, nonbollocks, nonshort] <*> mapChecks tags [nonempty, nonbollocks] <*> subValidator author userValidator userValidator :: Monad m => Validator User m UserError userValidator = User <$> checks username [nonempty, nonbollocks]  B is used when you are not interested in validating certain fields. )Check if a single condition is satisfied. *Check if mutiple conditions are satisfied. /Apply a single check to multiple values within  structure. )Apply a multiple checks to values within  structure.Apply a O instead of check to the field. This is useful when validating nested records.Once you have constructed your Y you can run it against your input data. If there were no validation errors you will get / wrapped in a monad of your choice as a result.Here is the result of running articleValidator against some bad data: çbadArticle :: Article badArticle = Article { id = 17 , title = "Some interesting title" , content = "bollocks" , tags = ["I'm ok", "me too", "bollocks"] , author = badUser } badUser :: User badUser = User "" ÿ5>>> validatePure articleValidator badArticle Just ( Article { id = Just "must be over 18" , title = Nothing , content = Just ["can't be bollocks","too short"] , tags = Just [Nothing,Nothing,Just ["can't be bollocks"]] , author = Just (User {username = Just ["can't be empty"]}) } )This will run your ) as a pure computation returning simple + instead of it being wrapped in some monad./Another simple utility function for converting  error this time into a .-Internal utility function for constructing a  from . ,just a dummy validator that always succeeds. field selectorcheck to be performedresulting validator field selectorlist of checksresulting validator field selectorcheck to be performedresulting validator field selectorlist of checksresulting validatorfield selector to run against field value resulting field selector to run against values resulting & that we want to run against the valuevalue that is being validated/final result wrapped in a monad of our choosing function to apply in case of !function to apply in case of "initial  resulting   !"#$Safe@%&'()*+,-      !"# $ %&'()*+,-./01234$valor-0.0.0.1-Bq46vv4XptPEfDJkGIGLzp Data.Valor Paths_valorbaseData.Functor.Identity runIdentityIdentitytransformers-0.5.2.0Control.Monad.Trans.ExceptthrowE runExceptTExceptTValidate Validatable ValidatorskipcheckchecksmapCheck mapChecks subValidatormapSubValidatorvalidate validatePure$fApplicativeValidated$fFunctorValidated$fSemigroupValidated$fApplicativeValidator$fFunctorValidator$fSemigroupValidator$fShowValidated ValidatedGHC.Base ApplicativeData.Traversable TraversableNothingMaybemconvert validator converterValidInvalid unValidatorversion getBinDir getLibDir getDynLibDir getDataDir getLibexecDir getSysconfDirgetDataFileName