{-# language GeneralizedNewtypeDeriving #-} {-# language RankNTypes #-} {-| Module : Data.Validate.Monadic Copyright : (C) CSIRO 2017-2019 License : BSD3 Maintainer : Isaac Elliott Stability : experimental Portability : non-portable -} module Data.Validate.Monadic ( ValidateM (ValidateM, unValidateM) , runValidateM , bindVM , liftVM0 , liftVM1 , errorVM , errorVM1 ) where import Data.Functor.Compose (Compose(..)) import Data.Semigroup (Semigroup) import Data.Validation (Validation(..)) -- | The composition of 'Data.Validation.Validation' with another 'Applicative' functor. -- -- 'Data.Validation.Validation' is not a 'Monad', and 'ValidateM' is not a monad transformer. -- It is equipped with a useful bind function, but that function does not have -- the right type to make 'ValidateM' a 'Monad' (besides which it would break -- the laws) newtype ValidateM e m a = ValidateM { unValidateM :: Compose m (Validation e) a } deriving (Functor, Applicative) -- | Unwrap a 'ValidateM' runValidateM :: ValidateM e m a -> m (Validation e a) runValidateM = getCompose . unValidateM -- | Bind into a 'ValidateM' bindVM :: Monad m => ValidateM e m a -> (a -> ValidateM e m b) -> ValidateM e m b bindVM m f = ValidateM . Compose $ do res <- getCompose $ unValidateM m case res of Failure err -> pure $ Failure err Success a -> getCompose . unValidateM $ f a -- | Lift into a succeeding validation liftVM0 :: (Functor m, Semigroup e) => m a -> ValidateM e m a liftVM0 m = ValidateM . Compose $ pure <$> m -- | Run a natural transformation across 'ValidateM' to alter @m@ liftVM1 :: (forall x. m x -> m x) -> ValidateM e m a -> ValidateM e m a liftVM1 f = ValidateM . Compose . f . getCompose . unValidateM -- | Lift an error into 'ValidateM' errorVM :: Applicative m => e -> ValidateM e m a errorVM = ValidateM . Compose . pure . Failure -- | Lift an error in an 'Applicative' into 'ValidateM'. This is especially -- useful if you're using list or 'Data.List.NonEmpty.NonEmpty' to collect errors. errorVM1 :: (Applicative f, Applicative m) => e -> ValidateM (f e) m a errorVM1 = errorVM . pure