Bitraversable Validation Source # Similar to Traversable but traverses both Failure and Success with given effectful computations. Examples >>> parseInt = readMaybe :: String -> 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 []) Nothing

Instance details Defined in Validation bitraverse :: Applicative f => (a -> f c) -> (b -> f d) -> Validation a b -> f (Validation c d) #

Bifoldable Validation Source # Similar to Foldable but allows folding both Failure and Success to the same monoidal value according to given functions. Examples >>> one x = [x] >>> bifoldMap id (one . show) (Success 15) ["15"] >>> bifoldMap id (one . show) (Failure ["Wrong", "Fail"]) ["Wrong","Fail"]

Instance details Defined in Validation bifold :: Monoid m => Validation m m -> m # bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> Validation a b -> m # bifoldr :: (a -> c -> c) -> (b -> c -> c) -> c -> Validation a b -> c # bifoldl :: (c -> a -> c) -> (c -> b -> c) -> c -> Validation a b -> c #

Bifunctor Validation Source # Similar to Functor but allows mapping of values inside both Failure and Success . Examples >>> bimap length show (Success 50) Success "50" >>> bimap length show (Failure ["15", "9"]) Failure 2

Instance details Defined in Validation bimap :: (a -> b) -> (c -> d) -> Validation a c -> Validation b d # first :: (a -> b) -> Validation a c -> Validation b c # second :: (b -> c) -> Validation a b -> Validation a c #

Instance details Defined in Validation liftRnf2 :: (a -> ()) -> (b -> ()) -> Validation a b -> () #

(NoValidationMonadError, (NoValidationMonadError, Semigroup e) => Monad Validation e) Source # ⚠️CAUTION⚠️ This instance is for custom error display only. It's not possible to implement lawful Monad instance for Validation . In case it is used by mistake, the user will see the following: >>> Success 42 >>=

-> 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'. ...

Instance details Defined in Validation (>>=) :: Validation e a -> (a -> Validation e b) -> Validation e b # (>>) :: Validation e a -> Validation e b -> Validation e b # return :: a -> Validation e a #

Functor ( Validation e) Source # Allows changing the value inside Success with a given function. Examples >>> fmap (+1) (Success 9) Success 10 >>> fmap (+1) (Failure ["wrong"]) Failure ["wrong"]

Instance details Defined in Validation fmap :: (a -> b) -> Validation e a -> Validation e b # (<$) :: a -> Validation e b -> Validation e a #

Semigroup e => Applicative Validation e) Source # This instance if the most important instance for the Validation 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] Int >>> success2 = Success 15 :: Validation [String] Int >>> successF = Success (* 2) :: Validation [String] (Int -> Int) >>> failure1 = Failure ["WRONG"] :: Validation [String] Int >>> failure2 = Failure ["FAIL"] :: Validation [String] Int >>> successF <*> success1 Success 18 >>> successF <*> failure1 Failure ["WRONG"] >>> (+) <$> success1 <*> success2 Success 24 >>> (+) <$> failure1 <*> failure2 Failure ["WRONG","FAIL"] >>> liftA2 (+) success1 failure1 Failure ["WRONG"] >>> liftA3 (,,) failure1 success1 failure2 Failure ["WRONG","FAIL"] Implementations of all functions are lazy and they correctly work if some arguments are not fully evaluated. >>> failure1 *> failure2 Failure ["WRONG","FAIL"] >>> isFailure $ failure1 *> failure2 True >>> epicFail = error "Impossible validation" :: Validation [String] Int >>> isFailure $ failure1 *> epicFail True

Instance details Defined in Validation pure :: a -> Validation e a # (<*>) :: Validation e (a -> b) -> Validation e a -> Validation e b # liftA2 :: (a -> b -> c) -> Validation e a -> Validation e b -> Validation e c # (*>) :: Validation e a -> Validation e b -> Validation e b # (<*) :: Validation e a -> Validation e b -> Validation e a #

Foldable ( Validation e) Source # Foldable for Validation allows folding values inside Success . Examples >>> fold (Success [16]) [16] >>> fold (Failure "WRONG!" :: Validation String [Int]) []

Instance details Defined in Validation fold :: Monoid m => Validation e m -> m # foldMap :: Monoid m => (a -> m) -> Validation e a -> m # foldMap' :: Monoid m => (a -> m) -> Validation e a -> m # foldr :: (a -> b -> b) -> b -> Validation e a -> b # foldr' :: (a -> b -> b) -> b -> Validation e a -> b # foldl :: (b -> a -> b) -> b -> Validation e a -> b # foldl' :: (b -> a -> b) -> b -> Validation e a -> b # foldr1 :: (a -> a -> a) -> Validation e a -> a # foldl1 :: (a -> a -> a) -> Validation e a -> a # toList :: Validation e a -> [a] # null :: Validation e a -> Bool # length :: Validation e a -> Int # elem :: Eq a => a -> Validation e a -> Bool # maximum :: Ord a => Validation e a -> a # minimum :: Ord a => Validation e a -> a # sum :: Num a => Validation e a -> a # product :: Num a => Validation e a -> a #

Traversable ( Validation e) Source # Traverse values inside Success 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"])

Instance details Defined in Validation traverse :: Applicative f => (a -> f b) -> Validation e a -> f (Validation e b) # sequenceA :: Applicative f => Validation e (f a) -> f (Validation e a) # mapM :: Monad m => (a -> m b) -> Validation e a -> m (Validation e b) # sequence :: Monad m => Validation e (m a) -> m (Validation e a) #

( Semigroup e, Monoid e) => Alternative Validation e) Source # This instance implements the behaviour when the first Success is returned. Otherwise all Failure s are combined. Examples >>> success1 = Success [9] :: Validation [String] [Int] >>> success2 = Success [15] :: Validation [String] [Int] >>> failure1 = Failure ["WRONG"] :: Validation [String] [Int] >>> failure2 = Failure ["FAIL"] :: Validation [String] [Int] >>> success1 <|> success2 Success [9] >>> failure1 <|> failure2 Failure ["WRONG","FAIL"] >>> failure2 <|> success2 Success [15]

Instance details Defined in Validation empty :: Validation e a # (<|>) :: Validation e a -> Validation e a -> Validation e a # some :: Validation e a -> Validation e [a] # many :: Validation e a -> Validation e [a] #

Instance details Defined in Validation liftRnf :: (a -> ()) -> Validation e a -> () #

Semigroup e => Selective Validation e) Source # Selective functors from the selective package. This instance allows choosing which validations to apply based on value inside. Validation can't have a lawful Monad instance but it's highly desirable to have the monadic behavior in cases when you want future checks depend on previous values. Selective allows to circumvent this limitation by providing the desired behavior. Examples Expand To understand better, how Selective 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 >>> :{ validateEmptyPassword :: String -> PasswordValidation validateEmptyPassword password = Password password <$ failureIf (null password) EmptyPassword :} >>> :{ validateShortPassword :: String -> PasswordValidation validateShortPassword password = Password password <$ failureIf (length password < 8) ShortPassword :} >>> :{ validatePasswordDigit :: String -> PasswordValidation validatePasswordDigit password = Password password <$ failureUnless (any isDigit password) NoDigitPassword :} And we can easily compose all these checks into single validation for Password using Applicative instance: >>> :{ validatePassword :: String -> PasswordValidation validatePassword 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 Applicative instance for Validation , 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 Validation , 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 Validation had the Monad instance. But it can't have a lawful Monad instance. Fortunately, the Selective instance for Validation 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: >>> :{ checkEmptyPassword :: 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 : >>> :{ validatePassword :: String -> PasswordValidation validatePassword 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"})

Instance details Defined in Validation select :: Validation e (Either a b) -> Validation e (a -> b) -> Validation e b #

Instance details Defined in Validation type Rep1 (Validation e) :: k -> Type # from1 :: forall (a :: k). Validation e a -> Rep1 (Validation e) a # to1 :: forall (a :: k). Rep1 (Validation e) a -> Validation e a #

Instance details Defined in Validation (==) :: Validation e a -> Validation e a -> Bool # (/=) :: Validation e a -> Validation e a -> Bool #

Instance details Defined in Validation gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Validation e a -> c (Validation e a) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Validation e a) # toConstr :: Validation e a -> Constr # dataTypeOf :: Validation e a -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (Validation e a)) # dataCast2 :: Typeable t => (forall d e0. (Data d, Data e0) => c (t d e0)) -> Maybe (c (Validation e a)) # gmapT :: (forall b. Data b => b -> b) -> Validation e a -> Validation e a # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Validation e a -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Validation e a -> r # gmapQ :: (forall d. Data d => d -> u) -> Validation e a -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Validation e a -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Validation e a -> m (Validation e a) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Validation e a -> m (Validation e a) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Validation e a -> m (Validation e a) #

Instance details Defined in Validation compare :: Validation e a -> Validation e a -> Ordering # (<) :: Validation e a -> Validation e a -> Bool # (<=) :: Validation e a -> Validation e a -> Bool # (>) :: Validation e a -> Validation e a -> Bool # (>=) :: Validation e a -> Validation e a -> Bool # max :: Validation e a -> Validation e a -> Validation e a # min :: Validation e a -> Validation e a -> Validation e a #

Instance details Defined in Validation showsPrec :: Int -> Validation e a -> ShowS # show :: Validation e a -> String # showList :: [Validation e a] -> ShowS #

Instance details Defined in Validation type Rep (Validation e a) :: Type -> Type # from :: Validation e a -> Rep (Validation e a) x # to :: Rep (Validation e a) x -> Validation e a #

( Semigroup e, Semigroup a) => Semigroup Validation e a) Source # Semigroup allows merging multiple Validation s into single one by combining values inside both Failure and Success . The <> operator merges two Validation s following the below rules: If both values are Failure s, returns a new Failure with accumulated errors. If both values are Success ful, returns a new Success with combined success using Semigroup for values inside Success . If one value is Failure and another one is Success , then Failure is returned. Examples >>> success1 = Success [9] :: Validation [String] [Int] >>> success2 = Success [15] :: Validation [String] [Int] >>> failure1 = Failure ["WRONG"] :: Validation [String] [Int] >>> failure2 = Failure ["FAIL"] :: Validation [String] [Int] >>> success1 <> success2 Success [9,15] >>> failure1 <> failure2 Failure ["WRONG","FAIL"] >>> success1 <> failure1 Failure ["WRONG"] >>> failure2 <> success1 <> success2 <> failure1 Failure ["FAIL","WRONG"]

Instance details Defined in Validation (<>) :: Validation e a -> Validation e a -> Validation e a # sconcat :: NonEmpty (Validation e a) -> Validation e a # stimes :: Integral b => b -> Validation e a -> Validation e a #

( Semigroup e, Semigroup a, Monoid a) => Monoid Validation e a) Source # mempty :: Validation e a is Success which stores mempty :: a to be consistent with the Semigroup instance. Examples >>> mempty :: Validation String [Bool] Success []

Instance details Defined in Validation mempty :: Validation e a # mappend :: Validation e a -> Validation e a -> Validation e a # mconcat :: [Validation e a] -> Validation e a #