h&CBe2      !"#$%&'()*+,-./01(c) 2020-2023 KowainikMPL-2.0Kowainik StablePortable Safe-Inferred"%&(/25;?{ validation-selectiveValidate all given checks in a 2. Returns the 5 of the start element when all checks are successful..A basic example of usage could look like this: > let validatePassword =  [ validateEmptyPassword , validateShortPassword ] >  "VeryStrongPassword"  "VeryStrongPassword" >  "" $ (EmptyPassword :| [ShortPassword]) validation-selectiveApplies the given action to  if it is $ and returns the result. In case of  the default value is returned.7whenFailure "bar" (Failure 42) (\a -> "foo" <$ print a)42"foo"7whenFailure "bar" (Success 42) (\a -> "foo" <$ print a)"bar"validation-selectiveApplies given action to the  content if it is . Similar to  but the default value is ()."whenFailure_ (Success 42) putStrLn%whenFailure_ (Failure "foo") putStrLnfoovalidation-selectiveMonadic version of &. Applies monadic action to the given  in case of 3. Returns the resulting value, or provided default.?whenFailureM "bar" (pure $ Failure 42) (\a -> "foo" <$ print a)42"foo"?whenFailureM "bar" (pure $ Success 42) (\a -> "foo" <$ print a)"bar"validation-selectiveMonadic version of &. Applies monadic action to the given  in case of  . Similar to  but the default is ().*whenFailureM_ (pure $ Success 42) putStrLn-whenFailureM_ (pure $ Failure "foo") putStrLnfoo validation-selectiveApplies the given action to  if it is $ and returns the result. In case of  the default value is returned.?whenSuccess "bar" (Failure "foo") (\a -> "success!" <$ print a)"bar" "success!" <$ print a)42 "success!" validation-selectiveApplies given action to the  content if it is . Similar to   but the default value is ()."whenSuccess_ (Failure "foo") printwhenSuccess_ (Success 42) print42 validation-selectiveMonadic version of  &. Applies monadic action to the given  in case of 3. Returns the resulting value, or provided default.whenSuccessM "bar" (pure $ Failure "foo") (\a -> "success!" <$ print a)"bar"whenSuccessM "bar" (pure $ Success 42) (\a -> "success!" <$ print a)42 "success!" validation-selectiveMonadic version of  &. Applies monadic action to the given  in case of  . Similar to   but the default is ().*whenSuccessM_ (pure $ Failure "foo") print'whenSuccessM_ (pure $ Success 42) print42 validation-selectiveMaps  of  to 3.failureToMaybe (Failure True) Just TruefailureToMaybe (Success "aba")Nothingvalidation-selectiveMaps  of  to 3.successToMaybe (Failure True)NothingsuccessToMaybe (Success "aba") Just "aba"validation-selectiveMaps 3 to  In case of 4' it wraps the given default value into . maybeToFailure True (Just "aba") Failure "aba"maybeToFailure True Nothing Success Truevalidation-selectiveMaps 3 to  . In case of 4' it wraps the given default value into  maybeToSuccess True (Just "aba") Success "aba"maybeToSuccess True Nothing Failure True        (c) 2014 Chris Allen, Edward Kmett (c) 2018-2023 KowainikMPL-2.0Kowainik StablePortable Safe-Inferred"%&(/1256;=?B'validation-selective is a polymorphic sum type for storing either all validation failures or validation success. Unlike 5&, which returns only the first error, " accumulates all errors using the 6 typeclass.Usually type variables in  e a are used as follows:e: is a list or set of failure messages or values of some error data type.a<: is some domain type denoting successful validation result.Some typical use-cases:  [7] UserEither list of 73 error messages or a validated value of a custom User type.  (8 UserValidationError) UserSimilar to previous example, but list of failures guaranteed to be non-empty in case of validation failure, and it stores values of some custom error type.validation-selectiveValidation failure. The e# type is supposed to implement the 6 instance.validation-selective%Successful validation result of type a.validation-selective"Transforms the value of the given  into x- using provided functions that can transform  and , value into the resulting type respectively. " world!") (show . (* 10))myValidation (Success 100)"1000"myValidation (Failure "Hello")"Hello world!"9validation-selective,Helper type family to produce error messagesvalidation-selective Transform a  into an 5.$validationToEither (Success "whoop") Right "whoop"#validationToEither (Failure "nahh") Left "nahh"validation-selective Transform an 5 into a ."eitherToValidation (Right "whoop")Success "whoop" eitherToValidation (Left "nahh")Failure "nahh"validation-selectivePredicate on if the given  is .isFailure (Failure 'e')TrueisFailure (Success 'a')Falsevalidation-selectivePredicate on if the given  is .isSuccess (Success 'a')TrueisSuccess (Failure 'e')Falsevalidation-selectiveFilters out all  values into the new list of es from the given list of s.!Note that the order is preserved.failures [Failure "Hello", Success 1, Failure "world", Success 2, Failure "!" ]["Hello","world","!"]validation-selectiveFilters out all  values into the new list of as from the given list of s.!Note that the order is preserved.successes [Failure "Hello", Success 1, Failure "world", Success 2, Failure "!" ][1,2]validation-selective Redistributes the given list of s into two lists of es and e/s, where the first list contains all values of s and the second one @ es correspondingly.!Note that the order is preserved.partitionValidations [Failure "Hello", Success 1, Failure "world", Success 2, Failure "!" ](["Hello","world","!"],[1,2])validation-selectiveReturns the contents of a $-value or a default value otherwise.)fromFailure "default" (Failure "failure") "failure"!fromFailure "default" (Success 1) "default"validation-selectiveReturns the contents of a $-value or a default value otherwise.fromSuccess 42 (Success 1)1"fromSuccess 42 (Failure "failure")42validation-selective Create a  of 8 list with a single given error.failure "I am a failure" Failure ("I am a failure" :| [])validation-selective Returns a # in case of the given predicate is : . Returns  () otherwise.&let shouldFail = (==) "I am a failure"7failureIf (shouldFail "I am a failure") "I told you so"Failure ("I told you so" :| [])2failureIf (shouldFail "I am NOT a failure") "okay" Success ()validation-selective Returns a  unless the given predicate is : . Returns  ()' in case of the predicate is satisfied. Similar to  with the reversed predicate.  p D  (not p) &let shouldFail = (==) "I am a failure" Maybe Int.bitraverse listToMaybe parseInt (Success "42")Just (Success 42)/bitraverse listToMaybe parseInt (Success "int")Nothing.bitraverse listToMaybe parseInt (Failure [15])Just (Failure 15),bitraverse listToMaybe parseInt (Failure [])Nothingvalidation-selective Similar to 2 but allows folding both  and 9 to the same monoidal value according to given functions.Examples one x = [x]&bifoldMap id (one . show) (Success 15)["15"]5bifoldMap id (one . show) (Failure ["Wrong", "Fail"])["Wrong","Fail"] validation-selective Similar to <* but allows mapping of values inside both  and .Examplesbimap length show (Success 50) Success "50"'bimap length show (Failure ["15", "9"]) Failure 2!validation-selectiveTraverse values inside ! with some effectful computation.Examples+parseInt = readMaybe :: String -> Maybe Int traverse parseInt (Success "42")Just (Success 42)!traverse parseInt (Success "int")Nothing"traverse parseInt (Failure ["42"])Just (Failure ["42"])"validation-selective2 for  allows folding values inside .Examplesfold (Success [16])[16]2fold (Failure "WRONG!" :: Validation String [Int])[]#validation-selective6This instance implements the behaviour when the first  is returned. Otherwise all s are combined.Examples3success1 = Success [9] :: Validation [String] [Int]4success2 = Success [15] :: Validation [String] [Int]9failure1 = Failure ["WRONG"] :: Validation [String] [Int]9failure2 = Failure ["FAIL"] :: Validation [String] [Int]success1 <|> success2 Success [9]failure1 <|> failure2Failure ["WRONG","FAIL"]failure2 <|> success2 Success [15]$validation-selective= functors from the  -https://hackage.haskell.org/package/selective selective package. This instance allows choosing which validations to apply based on value inside.  can't have a lawful > instance but it's highly desirable to have the monadic behavior in cases when you want future checks depend on previous values. = allows to circumvent this limitation by providing the desired behavior.ExamplesTo understand better, how = can be helpful, let's consider a typical usage example with validating passwords.:{newtype Password = Password { unPassword :: String } deriving stock (Show):}When user enters a password in some form, we want to check the following conditions: Password must not be empty.,Password must contain at least 8 characters.'Password must contain at least 1 digit.As in the previous usage example with form validation, let's introduce a custom data type to represent all possible errors.:{data PasswordValidationError = EmptyPassword | ShortPassword | NoDigitPassword deriving stock (Show):}And, again, we can implement independent functions to validate all these cases:type PasswordValidation = Validation (NonEmpty PasswordValidationError) Password:{5validateEmptyPassword :: String -> PasswordValidation5validateEmptyPassword password = Password password <$+ failureIf (null password) EmptyPassword:}:{5validateShortPassword :: String -> PasswordValidation5validateShortPassword password = Password password <$1 failureIf (length password < 8) ShortPassword:}:{5validatePasswordDigit :: String -> PasswordValidation5validatePasswordDigit password = Password password <$8 failureUnless (any isDigit password) NoDigitPassword:}And we can easily compose all these checks into single validation for Password using ? instance::{0validatePassword :: String -> PasswordValidationvalidatePassword password =" validateEmptyPassword password% *> validateShortPassword password% *> validatePasswordDigit password:}However, if we try using this function, we can notice a problem immediately:validatePassword "":Failure (EmptyPassword :| [ShortPassword,NoDigitPassword])Due to the nature of the ? instance for , we run all checks and combine all possible errors. But you can notice that if password is empty, it doesn't make sense to run other validations. The fact that the password is empty implies that password is shorter than 8 characters.You may say that check for empty password is redundant because empty password is a special case of a short password. However, when using , we want to display readable and friendly errors to users, so they know how to fix errors and can act correspondingly.+This behaviour could be achieved easily if  had the >& instance. But it can't have a lawful > instance. Fortunately, the = instance for  can help with our problem. But to solve it, we need to write our password validation in a slightly different way.First, we need to write a function that checks whether the password is empty::{1checkEmptyPassword :: String -> Validation e Bool#checkEmptyPassword = Success . null:}Now we can use the ifS function from the  selective$ package to branch on the result of checkEmptyPassword::{0validatePassword :: String -> PasswordValidationvalidatePassword password = ifS! (checkEmptyPassword password) (failure EmptyPassword) (validateShortPassword password *> validatePasswordDigit password):}:With this implementation we achieved our desired behavior:validatePassword ""Failure (EmptyPassword :| [])validatePassword "abc",Failure (ShortPassword :| [NoDigitPassword])validatePassword "abc123"Failure (ShortPassword :| [])validatePassword "security567"/Success (Password {unPassword = "security567"})%validation-selective5This instance is the most important instance for the  data type. It's responsible for the many implementations. And it allows to accumulate errors while performing validation or combining the results in the applicative style.Examples/success1 = Success 9 :: Validation [String] Int0success2 = Success 15 :: Validation [String] Int Int)7failure1 = Failure ["WRONG"] :: Validation [String] Int7failure2 = Failure ["FAIL"] :: Validation [String] IntsuccessF <*> success1 Success 18successF <*> failure1Failure ["WRONG"](+) <$> success1 <*> success2 Success 24(+) <$> failure1 <*> failure2Failure ["WRONG","FAIL"]liftA2 (+) success1 failure1Failure ["WRONG"]&liftA3 (,,) failure1 success1 failure2Failure ["WRONG","FAIL"]Implementations of all functions are lazy and they correctly work if some arguments are not fully evaluated.failure1 *> failure2Failure ["WRONG","FAIL"] isFailure $ failure1 *> failure2TrueepicFail = error "Impossible validation" :: Validation [String] Int isFailure $ failure1 *> epicFailTrue&validation-selective@ ::  e a is Success which stores @ :: a to be consistent with the 6 instance.Examples"mempty :: Validation String [Bool] Success []'validation-selective6 allows merging multiple 2s into single one by combining values inside both  and . The A operator merges two s following the below rules: If both values are s, returns a new  with accumulated errors.If both values are ful, returns a new  with combined success using 6 for values inside .If one value is  and another one is , then  is returned.Examples3success1 = Success [9] :: Validation [String] [Int]4success2 = Success [15] :: Validation [String] [Int]9failure1 = Failure ["WRONG"] :: Validation [String] [Int]9failure2 = Failure ["FAIL"] :: Validation [String] [Int]success1 <> success2Success [9,15]failure1 <> failure2Failure ["WRONG","FAIL"]success1 <> failure1Failure ["WRONG"],failure2 <> success1 <> success2 <> failure1Failure ["FAIL","WRONG"](validation-selective!Allows changing the value inside  with a given function.Examplesfmap (+1) (Success 9) Success 10fmap (+1) (Failure ["wrong"])Failure ["wrong"])validation-selectiveMCAUTION2M This instance is for custom error display only.&It's not possible to implement lawful > instance for .?In case it is used by mistake, the user will see the following:Success 42 >>= \n -> if even n then Success n else Failure ["Not even"]...:... Type 'Validation' doesn't have lawful 'Monad' instance which means that you can't use 'Monad' methods with 'Validation'....            !"#$%&'()*+,-./01234564784794:;4<=4<>4<?@ABC4DE4<FGHI4<J4<K4<L4<M3validation-selective-0.2.0.0-5nF29cXFH7PKs0yF5r81Yo ValidationValidation.CombinatorsFailureSuccess validation validateAll whenFailure whenFailure_ whenFailureM whenFailureM_ whenSuccess whenSuccess_ whenSuccessM whenSuccessM_failureToMaybesuccessToMaybemaybeToFailuremaybeToSuccessvalidationToEithereitherToValidation isFailure isSuccessfailures successespartitionValidations fromFailure fromSuccessfailure failureIf failureUnless$fNFData2Validation$fBitraversableValidation$fBifoldableValidation$fBifunctorValidation$fTraversableValidation$fFoldableValidation$fAlternativeValidation$fSelectiveValidation$fApplicativeValidation$fMonoidValidation$fSemigroupValidation$fFunctorValidation$fMonadValidation$fEqValidation$fOrdValidation$fShowValidation$fGenericValidation$fGeneric1TYPEValidation$fDataValidation$fNFDataValidation$fNFData1Validationbase Data.FoldableFoldable GHC.MaybeJustNothing Data.EitherEitherGHC.Base SemigroupStringNonEmptyNoValidationMonadErrorghc-prim GHC.TypesTrueData.Traversable TraversableFunctor$selective-0.6-Dl8uh62GEv2GmqpYCS5UzDControl.Selective SelectiveMonad Applicativemempty<>