Validation-0.0.2: Data/Validation.hs
{-# LANGUAGE DeriveDataTypeable #-}
-- | Data types similar to @Data.Either@ that are explicit about failure and success.
module Data.Validation
(
AccValidation
, Validation
, ValidationT(..)
, Validate(..)
, FoldValidate(..)
, fromFailure
, fromSuccess
, getFailure
, getSuccess
, getFailureOr
, getSuccessOr
) where
import Control.Functor.Pointed
import Control.Applicative
import Data.Semigroup
import Data.Maybe
import Data.Typeable
import Data.Data
-- | A value of the type @err@ or @a@, however, the @Applicative@ instance
-- accumulates values. This is witnessed by the @Semigroup@ context on the instance.
-- /Note that there is no @Monad@ such that @ap = (<*>)./
--
-- * @success (+1) <*> success 7 == AccSuccess 8@
--
-- * @failure ["f1"] <*> success 7 == AccFailure ["f1"]@
--
-- * @success (+1) <*> failure ["f2"] == AccFailure ["f2"]@
--
-- * @failure ["f1"] <*> failure ["f2"] == AccFailure ["f1","f2"]@
data AccValidation err a =
AccFailure err
| AccSuccess a
deriving (Eq, Ord, Show, Data, Typeable)
instance Functor (AccValidation err) where
fmap _ (AccFailure e) = AccFailure e
fmap f (AccSuccess a) = AccSuccess (f a)
instance Pointed (AccValidation err) where
point = AccSuccess
instance Semigroup err => Applicative (AccValidation err) where
pure = point
AccFailure e1 <*> AccFailure e2 = AccFailure (e1 .++. e2)
AccFailure e1 <*> AccSuccess _ = AccFailure e1
AccSuccess _ <*> AccFailure e2 = AccFailure e2
AccSuccess f <*> AccSuccess a = AccSuccess (f a)
-- | A value of the type @err@ or @a@ and isomorphic to @Data.Either@.
data Validation err a =
Failure err
| Success a
deriving (Eq, Ord, Show, Data, Typeable)
instance Functor (Validation err) where
fmap _ (Failure e) = Failure e
fmap f (Success a) = Success (f a)
instance Pointed (Validation err) where
point = Success
instance Applicative (Validation err) where
pure = point
Failure e1 <*> Failure _ = Failure e1
Failure e1 <*> Success _ = Failure e1
Success _ <*> Failure e2 = Failure e2
Success f <*> Success a = Success (f a)
instance Monad (Validation err) where
return = point
Failure e >>= _ = Failure e
Success a >>= f = f a
-- | The transformer version of @Validation@.
data ValidationT m err a =
ValidationT {
runValidationT :: m (Validation err a)
}
instance Functor m => Functor (ValidationT m err) where
fmap f (ValidationT k) =
ValidationT (fmap (fmap f) k)
instance Pointed m => Pointed (ValidationT m err) where
point = ValidationT . point . point
instance Applicative m => Applicative (ValidationT m err) where
pure = ValidationT . pure . point
ValidationT f <*> ValidationT a = ValidationT (liftA2 (<*>) f a)
instance Monad m => Monad (ValidationT m err) where
return = ValidationT . return . point
ValidationT v >>= f = ValidationT (v >>= \w -> case w
of Failure e -> return (Failure e)
Success a -> runValidationT (f a))
-- | Construction for validation values.
class Validate v where
-- | Construct a success validation value.
success ::
a
-> v err a
-- | Construct a failure validation value.
failure ::
err
-> v err a
-- | Reduction for validation values.
class FoldValidate v where
-- | Reduce a validation value /(catamorphism)/.
foldValidate ::
(err -> x) -- ^ The function to run if a failure value.
-> (a -> x) -- ^ The function to run if a success value.
-> v err a -- ^ The validation value.
-> x
instance Validate AccValidation where
success =
point
failure =
AccFailure
instance FoldValidate AccValidation where
foldValidate f _ (AccFailure err) =
f err
foldValidate _ g (AccSuccess a) =
g a
instance Validate Validation where
success =
point
failure =
Failure
instance FoldValidate Validation where
foldValidate f _ (Failure err) =
f err
foldValidate _ g (Success a) =
g a
instance Pointed m => Validate (ValidationT m) where
success =
ValidationT . point . success
failure =
ValidationT . point . failure
-- | Returns the failure value or runs the given function on the success value to get a failure value.
fromFailure ::
FoldValidate v =>
(a -> err) -- ^ The function to run on the success value.
-> v err a
-> err
fromFailure =
foldValidate id
-- | Returns the success value or runs the given function on the failure value to get a success value.
fromSuccess ::
FoldValidate v =>
(err -> a) -- ^ The function to run on the failure value.
-> v err a
-> a
fromSuccess =
flip foldValidate id
-- | Returns the possible failure value if there is one.
getFailure ::
FoldValidate v =>
v err a
-> Maybe err
getFailure =
foldValidate Just (const Nothing)
-- | Returns the possible success value if there is one.
getSuccess ::
FoldValidate v =>
v err a
-> Maybe a
getSuccess =
foldValidate (const Nothing) Just
-- | Returns the failure value if there is one, otherwise returns the given default.
getFailureOr ::
FoldValidate v =>
err -- ^ The default to return if there is no failure value to return.
-> v err a
-> err
getFailureOr e =
fromMaybe e . getFailure
-- | Returns the success value if there is one, otherwise returns the given default.
getSuccessOr ::
FoldValidate v =>
a -- ^ The default to return if there is no success value to return.
-> v err a
-> a
getSuccessOr a =
fromMaybe a . getSuccess