{-# OPTIONS_HADDOCK not-home #-}
{-# LANGUAGE UndecidableInstances #-}

-- | __This is an internal module.__ Backwards compatibility will not be maintained. See
-- "Control.Monad.Validate" for the public interface.
module Control.Monad.Validate.Internal where

import Control.Monad ((<=<))
import Control.Monad.IO.Class
import Control.Monad.Base
import Control.Monad.Catch
import Control.Monad.Except
import Control.Monad.Fix
import Control.Monad.Reader.Class
import Control.Monad.State.Strict
import Control.Monad.Trans.Control
import Control.Monad.Writer.Class
import Data.Functor
import Data.Functor.Identity
import Data.Tuple (swap)

import Control.Monad.Validate.Class

{-| 'ValidateT' is a monad transformer for writing validations. Like 'ExceptT', 'ValidateT' is
primarily concerned with the production of errors, but it differs from 'ExceptT' in that 'ValidateT'
is designed not to necessarily halt on the first error. Instead, it provides a mechanism for
collecting many warnings or errors, ideally as many as possible, before failing. In that sense,
'ValidateT' is also somewhat like 'Control.Monad.Writer.WriterT', but it is not /just/ a combination
of 'ExceptT' and 'Control.Monad.Writer.WriterT'. Specifically, it differs in the following two
respects:

  1. 'ValidateT' automatically collects errors from all branches of an 'Applicative' expression,
     making it possible to write code in the same style that one would use with 'ExceptT' and
     automatically get additional information for free. (This is especially true when used in
     combination with the @ApplicativeDo@ language extension.)

  2. 'ValidateT' provides error signaling operators, 'refute' and 'dispute', which are similar to
     'throwError' and 'tell', respectively. However, both operators combine raised errors into a
     single value (using an arbitrary 'Semigroup'), so the relative ordering of validation errors is
     properly respected. (Of course, if the order doesn’t matter to you, you can choose to
     accumulate errors into an unordered container.)

== An introduction to 'ValidateT'

The first of the above two points is by far the most interesting feature of 'ValidateT'. Let’s make
it more concrete with an example:

@
>>> 'runValidate' ('refute' ["bang"] '*>' 'refute' ["boom"])
'Left' ["bang", "boom"]
@

At first blush, the above example may lead you to believe that 'refute' is like 'tell' from
'Control.Monad.Writer.WriterT', but it is actually more like 'throwError'. Consider its type:

@
'refute' :: 'MonadValidate' e m => e -> m a
@

Note that, like 'throwError', 'refute' is polymorphic in its return type, which is to say it never
returns. Indeed, if we introduce a dependency on a computation that fails using 'refute' via
'>>=', the downstream computation will not be run:

@
>>> let getString = 'refute' ["bang"] '*>' 'pure' "boom"
        useString a = 'refute' [a]
    in 'runValidate' (getString '>>=' useString)
'Left' ["bang"]
@

This works because although the 'Monad' instance for 'ValidateT' fails as soon as the first 'refute'
is executed (as it must due to the way the second argument of '>>=' depends on the result of its
first argument), the 'Applicative' instance runs all branches of '<*>' and combines the errors
produced by all of them. When @ApplicativeDo@ is enabled, this can lead to some “magical” looking
error reporting where validation automatically continues on each sub-piece of a piece of data until
it absolutely cannot proceed any further. As an example, this package’s test suite includes the
following function:

@
validateQueryRequest :: ('MonadReader' Env m, 'MonadValidate' [Error] m) => Value -> m QueryRequest
validateQueryRequest req = withObject "request" req '$' \o -> do
  qrAuth           <- withKey o "auth_token" parseAuthToken
  ~(qrTable, info) <- withKey o "table" parseTableName
  qrQuery          <- withKey o "query" parseQuery
  'Data.Foldable.for_' info '$' \tableInfo -> pushPath "query" '$'
    validateQuery qrTable tableInfo (atIsAdmin qrAuth) qrQuery
  'pure' QueryRequest { qrAuth, qrTable, qrQuery }
@

The above @do@ block parses and validates some JSON, and it’s written as straight line code, but
with @ApplicativeDo@ enabled (along with the @-foptimal-applicative-do@ option, which makes GHC try
a little harder), it still produces errors for all parts of the input document at once:

@
>>> 'flip' 'Control.Monad.Reader.runReader' env '.' 'runValidateT' '$' validateQueryRequest [aesonQQ|
      { "auth_token": 123
      , "table": { "name": "users" }
      , "query": { "add":
        [ { "lit": "42" }
        , { "select": "points" } ]}
      }|]
'Left' [ Error ["auth_token"] (JSONBadValue "string" (Number 123))
     , Error ["table"] (JSONMissingKey "schema")
     , Error ["query", "add", "lit"] (JSONBadValue "number" (String "42")) ]
@

The penultimate statement in the @do@ block—the one with the call to @validateQuery@—depends on
several of the bindings bound earlier in the same @do@ block, namely @qrAuth@, @info@, and
@qrQuery@. Because of that, @validateQuery@ will not be executed so long as any of its dependencies
fail. As soon as they all succeed, their results will be passed to @validateQuery@ as usual, and
validation will continue.

== The full details

Although 'ValidateT' (with @ApplicativeDo@) may seem magical, of course, it is not. As alluded to
above, 'ValidateT' simply provides a '<*>' implementation that collects errors produced by both
arguments rather than short-circuiting as soon as the first error is raised.

However, that explanation alone may raise some additional questions. What about the monad laws? When
'ValidateT' is used in a monad transformer stack, what happens to side effects? And what are
'ValidateT'’s performance characteristics? The remainder of this section discusses those topics.

=== 'ValidateT' and the 'Monad' laws

'ValidateT'’s 'Applicative' and 'Monad' instances do not conform to a strict interpretation of the
'Monad' laws, which dictate that '<*>' must be equivalent to 'ap'. For 'ValidateT', this is not true
if we consider “equivalent” to mean '=='. However, if we accept a slightly weaker notion of
equivalence, we can satisfy the laws. Specifically, we may use the definition that some 'Validate'
action @a@ is equivalent to another action @b@ iff

  * if @'runValidate' a@ produces @'Right' x@, then @'runValidate' b@ must produce @'Right' y@ where
    @x '==' y@ (and '==' is the usual Haskell '=='),

  * and if @'runValidate' a@ produces @'Left' x@, then @'runValidate' b@ must produce @'Left' y@
    (but @x@ and @y@ may be unrelated).

In other words, our definition of equivalence is like '==', except that we make no guarantees about
the /contents/ of an error should one occur. However, we /do/ guarantee that replacing '<*>' with
'ap' or vice versa will never change an error to a success or a success to an error, nor will it
change the value of a successful result in any way. To put it another way, 'ValidateT' provides
“best effort” error reporting: it will never return fewer errors than an equivalent use of
'ExceptT', but it might return more.

=== Using 'ValidateT' with other monad transformers

'ValidateT' is a valid, lawful, generally well-behaved monad transformer, and it is safe to use
within a larger monad transformer stack. Instances for the most common @mtl@-style typeclasses are
provided. __However__, be warned: many common monad transformers do not have sufficiently
order-independent 'Applicative' instances for 'ValidateT'’s 'Applicative' instance to actually
collect errors from multiple branches of a computation.

To understand why that might be, consider that 'StateT' must enforce a left-to-right evaluation
order for '<*>' in order to thread the state through the computation. If the @a@ action in an
expression @a '<*>' b@ fails, then it is simply not possible to run @b@ since @b@ may still depend
on the state that would have been produced by @a@. Similarly, 'ExceptT' enforces a left-to-right
evaluation because it aborts a computation as soon as an error is thrown. Using 'ValidateT' with
these kinds of monad transformers will cause it to effectively degrade to
'Control.Monad.Writer.WriterT' over 'ExceptT' since it will not be able to gather any errors
produced by 'refute' beyond the first one.

However, even that isn’t the whole story, since the relative order of monads in a monad transformer
stack can affect things further. For example, while the 'StateT' monad transformer enforces
left-to-right evaluation order, it only does this for the monad /underneath/ it, so although
@'StateT' s ('ValidateT' e)@ will not be able to collect multiple errors, @'ValidateT' e
('State' s)@ will. Note, however, that those two types differ in other ways, too—running each to
completion results in different types:

@
'runState' ('runValidateT' m) s :: ('Either' e a, s)
'runValidate' ('runStateT' m s) :: 'Either' e (a, s)
@

That kind of difference is generally true when using monad transformers—the two combinations of
'ExceptT' and 'StateT' have the same types as above, for example—but because 'ValidateT' needs to be
on top of certain transformers for it to be useful, combining 'ValidateT' with certain transformers
may be of little practical use.

One way to identify which monad transformers are uncooperative in the aforementioned way is to look
at the constraints included in the context of the transformer’s 'Applicative' instance. Transformers
like 'Control.Monad.State.StateT' have instances of the shape

@
instance 'Monad' m => 'Applicative' ('StateT' s m)
@

which notably require 'Monad' instances just to implement 'Applicative'! However, this is not always
sufficient for distinguishing which functions or instances use '<*>' and which use '>>=', especially
since many older libraries (which predate 'Applicative') may include 'Monad' contraints even when
they only use features of 'Applicative'. The only way to be certain is to examine the
implementation (or conservatively write code that is explicitly restricted to 'Applicative').

(As it happens, 'ValidateT'’s 'Applicative' is actually one such “uncooperative” instance itself: it
has a 'Monad' constraint in its context. It is possible to write an implementation of 'ValidateT'
without that constraint, but its '<*>' would necessarily leak space in the same way
'Control.Monad.Writer.WriterT'’s '>>=' leaks space. If you have a reason to want the less efficient
but more permissive variant, please let the author of this library know, as she would probably find
it interesting.)

== Performance characteristics of 'ValidateT'

Although the interface to 'ValidateT' is minimal, there are surprisingly many different ways to
implement it, each with its own set of performance tradeoffs. Here is a quick summary of the choices
'ValidateT' makes:

  1. 'ValidateT' is __strict__ in the set of errors it accumulates, which is to say it reduces them
     to weak head normal form (WHNF) via 'seq' immediately upon any call to 'refute' or 'dispute'.

  2. Furthermore, all of 'ValidateT'’s operations, including '<*>', operate in __constant space__.
     This means, for example, that evaluating @'sequence_' xs@ will consume constant space
     regardless of the size of @xs@, not counting any space consumed purely due to the relevant
     'Foldable' instance’s traversal of @xs@.

  3. Finally, 'ValidateT' accumulates errors in a __left-associative__ manner, which is to say that
     any uses of 'refute' or 'dispute' combine the existing set of errors, @e@, with the added set
     of errors, @e'@, via the expression @e '<>' e'@.

A good rule of thumb is that 'ValidateT' has similar performance characteristics to
@'Data.Foldable.foldl'' ('<>')@, while types like @Validation@ from the @either@ package tend to
have similar performance characteristics to @'foldr' ('<>')@. That decision has both significant
advantages and significant disadvantages; the following subsections elaborate further.

=== '<*>' takes constant space

Great care has been taken in the implementation of '<*>' to ensure it does not leak space. Notably,
the same /cannot/ be said for many existing implementations of similar concepts. For example, you
will find that executing the expression

@
let m () = 'pure' () '*>' m () in m ()
@

may continuously allocate memory until it is exhausted for types such as @Validation@ (from the
@either@ package), but 'ValidateT' will execute it in constant space. This point may seem silly,
since the above definition of @m ()@ will never do anything useful, anyway, but the same point also
applies to operations like 'sequence_'.

In practice, this issue matters far less for types like @Validation@ than it does for 'ValidateT',
as @Validation@ and its cousins don’t have a 'Monad' instance and do not generally experience the
same usage patterns. (The additional laziness they are capable of can sometimes even avoid the space
leak altogether.) However, it can be relevant more often for 'ValidateT', so this implementation
makes choices to avoid the potential for the leak altogether.

=== Errors are accumulated using strict, left-associated '<>'

A major consequence of the decision to both strictly accumulate state and maintain constant space is
that 'ValidateT'’s internal applications of '<>' to combine errors are naturally strict and
left-associated, not lazy and right-associated like they are for types like @Validation@. If the
number of errors your validation generates is small, this difference is irrelevant, but if it is
large, the difference in association can prove disastrous if the 'Semigroup' you choose to
accumulate errors in is @[a]@!

To make it painfully explicit why using @[a]@ can come back to bite you, consider that each time
'ValidateT' executes @'refute' e'@, given some existing collection of errors @e@, it (strictly)
evalutes @e '<>' e'@ to obtain a new collection of errors. Now consider the implications of that
if @e@ is a ten thousand element list: '<>' will have to traverse /all/ ten thousand elements and
reallocate a fresh cons cell for every single one in order to build the new list, even if just one
element is being appended to the end! Unfortunately, the ubiquitous, built-in @[a]@ type is clearly
an exceptionally poor choice for this pattern of accumulation.

Fortunately, the solution is quite simple: use a different data structure. If order doesn’t matter,
use a @Set@ or @HashSet@. If it does, but either LIFO consumption of the data is okay or you are
okay with paying to reverse the data once after collecting the errors, use @'Data.Semigroup.Dual'
[a]@ to accumulate elements in an efficient manner. If neither is true, use a data structure like
@Seq@ that provides an efficient implementation of a functional queue. You can always convert back
to a plain list at the end once you’re done, if you have to. -}
newtype ValidateT e m a = ValidateT
  { forall e (m :: * -> *) a.
ValidateT e m a
-> forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
getValidateT :: forall s. StateT (MonoMaybe s e) (ExceptT e m) a }
-- Sadly, GeneralizedNewtypeDeriving can’t help us here due to the inner forall, but we can at least
-- derive the Functor instance.
deriving instance (Functor m) => Functor (ValidateT e m)

validateT
  :: forall e m a. (Functor m)
  => (forall s. MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
  -> ValidateT e m a
validateT :: forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall (s :: MonoMaybeS).
MonoMaybe s e -> m (Either e (MonoMaybe s e, a))
f = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT (forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
StateT (forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> (b, a)
swap) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (s :: MonoMaybeS).
MonoMaybe s e -> m (Either e (MonoMaybe s e, a))
f)))
{-# INLINE validateT #-}

unValidateT
  :: forall s e m a. (Functor m)
  => MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT :: forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s e
e (ValidateT forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m) = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (forall a b. (a, b) -> (b, a)
swap forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m MonoMaybe s e
e)
{-# INLINE unValidateT #-}

instance (Monad m) => Applicative (ValidateT e m) where
  pure :: forall a. a -> ValidateT e m a
pure a
v = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT (forall (f :: * -> *) a. Applicative f => a -> f a
pure a
v)
  {-# INLINE pure #-}

  ValidateT e m (a -> b)
m1 <*> :: forall a b.
ValidateT e m (a -> b) -> ValidateT e m a -> ValidateT e m b
<*> ValidateT e m a
m2 = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e0 ->
    forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s e
e0 ValidateT e m (a -> b)
m1 forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Left e
e1 -> forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT (forall (s :: MonoMaybeS) a. a -> MonoMaybe s a
MJust @'SJust e
e1) ValidateT e m a
m2 forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
        Left e
e2 -> forall a b. a -> Either a b
Left e
e2
        Right (MJust e
e2, a
_) -> forall a b. a -> Either a b
Left e
e2
      Right (MonoMaybe s e
e1, a -> b
v1) -> forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s e
e1 ValidateT e m a
m2 forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
        Left e
e2 -> forall a b. a -> Either a b
Left e
e2
        Right (MonoMaybe s e
e2, a
v2) -> forall a b. b -> Either a b
Right (MonoMaybe s e
e2, a -> b
v1 a
v2)
  {-# INLINABLE (<*>) #-}

instance (Monad m) => Monad (ValidateT e m) where
  ValidateT forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m >>= :: forall a b.
ValidateT e m a -> (a -> ValidateT e m b) -> ValidateT e m b
>>= a -> ValidateT e m b
f = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT (forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \a
x -> forall e (m :: * -> *) a.
ValidateT e m a
-> forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
getValidateT (a -> ValidateT e m b
f a
x))
  {-# INLINE (>>=) #-}

instance MonadTrans (ValidateT e) where
  lift :: forall (m :: * -> *) a. Monad m => m a -> ValidateT e m a
lift m a
m = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT (forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m a
m)
  {-# INLINE lift #-}

instance (MonadFix m) => MonadFix (ValidateT e m) where
  mfix :: forall a. (a -> ValidateT e m a) -> ValidateT e m a
mfix a -> ValidateT e m a
f = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFix m => (a -> m a) -> m a
mfix (\a
x -> forall e (m :: * -> *) a.
ValidateT e m a
-> forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
getValidateT (a -> ValidateT e m a
f a
x))
  {-# INLINE mfix #-}

instance (MonadIO m) => MonadIO (ValidateT e m) where
  liftIO :: forall a. IO a -> ValidateT e m a
liftIO = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
  {-# INLINE liftIO #-}

instance (MonadBase b m) => MonadBase b (ValidateT e m) where
  liftBase :: forall α. b α -> ValidateT e m α
liftBase = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (b :: * -> *) (m :: * -> *) α. MonadBase b m => b α -> m α
liftBase
  {-# INLINE liftBase #-}

-- | An opaque type used to capture the current state of a 'ValidateT' computation, used as the
-- 'StT' instance for 'ValidateT'. It is opaque in an attempt to protect internal invariants about
-- the state, but it is unfortunately still theoretically possible for it to be misused (but such
-- misuses are exceedingly unlikely).
data ValidateTState e a = forall s. ValidateTState
  { ()
getValidateTState :: Either e (MonoMaybe s e, a) }
deriving instance (Show e, Show a) => Show (ValidateTState e a)
deriving instance Functor (ValidateTState e)

instance MonadTransControl (ValidateT e) where
  type StT (ValidateT e) a = ValidateTState e a

  liftWith :: forall (m :: * -> *) a.
Monad m =>
(Run (ValidateT e) -> m a) -> ValidateT e m a
liftWith Run (ValidateT e) -> m a
f = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e ->
    forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MonoMaybe s e
e,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Run (ValidateT e) -> m a
f (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall e a (s :: MonoMaybeS).
Either e (MonoMaybe s e, a) -> ValidateTState e a
ValidateTState forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s e
e)
  {-# INLINABLE liftWith #-}

  restoreT :: forall (m :: * -> *) a.
Monad m =>
m (StT (ValidateT e) a) -> ValidateT e m a
restoreT m (StT (ValidateT e) a)
m = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e1 -> do
    ValidateTState Either e (MonoMaybe s e, a)
r <- m (StT (ValidateT e) a)
m
    case MonoMaybe s e
e1 of
      MonoMaybe s e
MNothing -> case Either e (MonoMaybe s e, a)
r of
        Left e
e2             -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left e
e2
        Right (MJust e
e2, a
v) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right (forall (s :: MonoMaybeS) a. a -> MonoMaybe s a
MJust e
e2, a
v)
        Right (MonoMaybe s e
MNothing, a
v) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right (forall a. MonoMaybe 'SMaybe a
MNothing, a
v)
      MJust e
_ -> case Either e (MonoMaybe s e, a)
r of
        Left e
e2             -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left e
e2
        Right (MJust e
e2, a
v) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right (forall (s :: MonoMaybeS) a. a -> MonoMaybe s a
MJust e
e2, a
v)
        Right (MonoMaybe s e
MNothing, a
_) -> forall a. a
invalidRestoreError
  {-# INLINABLE restoreT #-}

invalidRestoreError :: a
invalidRestoreError :: forall a. a
invalidRestoreError = forall a. HasCallStack => String -> a
error
  String
"Control.Monad.Validate.ValidateT#restoreT: panic!\n\
  \  An attempt was made to restore from a state captured before any validation\n\
  \  errors occurred into a context with validation errors. This is probably the\n\
  \  result of an incorrect use of MonadBaseControl (as validation errors should\n\
  \  strictly increase). Ensure that all state is restored immediately upon\n\
  \  returning from the base monad (or is not restored at all).\n\
  \\n\
  \  If you believe your use of MonadBaseControl is not in error, and this is a\n\
  \  bug in ValidateT, please submit a bug report."

instance (MonadBaseControl b m) => MonadBaseControl b (ValidateT e m) where
  type StM (ValidateT e m) a = ComposeSt (ValidateT e) m a
  liftBaseWith :: forall a. (RunInBase (ValidateT e m) b -> b a) -> ValidateT e m a
liftBaseWith = forall (t :: (* -> *) -> * -> *) (b :: * -> *) (m :: * -> *) a.
(MonadTransControl t, MonadBaseControl b m) =>
(RunInBaseDefault t m b -> b a) -> t m a
defaultLiftBaseWith
  restoreM :: forall a. StM (ValidateT e m) a -> ValidateT e m a
restoreM = forall (t :: (* -> *) -> * -> *) (b :: * -> *) (m :: * -> *) a.
(MonadTransControl t, MonadBaseControl b m) =>
ComposeSt t m a -> t m a
defaultRestoreM
  {-# INLINE liftBaseWith #-}
  {-# INLINE restoreM #-}

liftCatch
  :: (Functor m)
  => (forall b. m b -> (e -> m b) -> m b)
  -> ValidateT d m a -> (e -> ValidateT d m a) -> ValidateT d m a
liftCatch :: forall (m :: * -> *) e d a.
Functor m =>
(forall b. m b -> (e -> m b) -> m b)
-> ValidateT d m a -> (e -> ValidateT d m a) -> ValidateT d m a
liftCatch forall b. m b -> (e -> m b) -> m b
catchE ValidateT d m a
m e -> ValidateT d m a
f = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s d
e ->
  forall b. m b -> (e -> m b) -> m b
catchE (forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s d
e ValidateT d m a
m) (forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s d
e forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> ValidateT d m a
f)
{-# INLINE liftCatch #-}

instance (MonadError e m) => MonadError e (ValidateT a m) where
  throwError :: forall a. e -> ValidateT a m a
throwError = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError
  catchError :: forall a.
ValidateT a m a -> (e -> ValidateT a m a) -> ValidateT a m a
catchError = forall (m :: * -> *) e d a.
Functor m =>
(forall b. m b -> (e -> m b) -> m b)
-> ValidateT d m a -> (e -> ValidateT d m a) -> ValidateT d m a
liftCatch forall e (m :: * -> *) a.
MonadError e m =>
m a -> (e -> m a) -> m a
catchError
  {-# INLINE throwError #-}
  {-# INLINE catchError #-}

instance (MonadReader r m) => MonadReader r (ValidateT e m) where
  ask :: ValidateT e m r
ask = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall r (m :: * -> *). MonadReader r m => m r
ask
  local :: forall a. (r -> r) -> ValidateT e m a -> ValidateT e m a
local r -> r
f (ValidateT forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m) = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT (forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local r -> r
f forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m)
  reader :: forall a. (r -> a) -> ValidateT e m a
reader = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
reader
  {-# INLINE ask #-}
  {-# INLINE local #-}
  {-# INLINE reader #-}

instance (MonadState s m) => MonadState s (ValidateT e m) where
  get :: ValidateT e m s
get = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall s (m :: * -> *). MonadState s m => m s
get
  put :: s -> ValidateT e m ()
put = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *). MonadState s m => s -> m ()
put
  state :: forall a. (s -> (a, s)) -> ValidateT e m a
state = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
state
  {-# INLINE get #-}
  {-# INLINE put #-}
  {-# INLINE state #-}

instance (MonadWriter w m) => MonadWriter w (ValidateT e m) where
  writer :: forall a. (a, w) -> ValidateT e m a
writer = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *) a. MonadWriter w m => (a, w) -> m a
writer
  tell :: w -> ValidateT e m ()
tell = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell
  listen :: forall a. ValidateT e m a -> ValidateT e m (a, w)
listen (ValidateT forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m) = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT (forall w (m :: * -> *) a. MonadWriter w m => m a -> m (a, w)
listen forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
m)
  pass :: forall a. ValidateT e m (a, w -> w) -> ValidateT e m a
pass (ValidateT forall (s :: MonoMaybeS).
StateT (MonoMaybe s e) (ExceptT e m) (a, w -> w)
m) = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT (forall w (m :: * -> *) a. MonadWriter w m => m (a, w -> w) -> m a
pass forall (s :: MonoMaybeS).
StateT (MonoMaybe s e) (ExceptT e m) (a, w -> w)
m)
  {-# INLINE writer #-}
  {-# INLINE tell #-}
  {-# INLINE listen #-}
  {-# INLINE pass #-}

instance (MonadThrow m) => MonadThrow (ValidateT e m) where
  throwM :: forall e a. Exception e => e -> ValidateT e m a
throwM = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM
  {-# INLINE throwM #-}

instance (MonadCatch m) => MonadCatch (ValidateT e m) where
  catch :: forall e a.
Exception e =>
ValidateT e m a -> (e -> ValidateT e m a) -> ValidateT e m a
catch = forall (m :: * -> *) e d a.
Functor m =>
(forall b. m b -> (e -> m b) -> m b)
-> ValidateT d m a -> (e -> ValidateT d m a) -> ValidateT d m a
liftCatch forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch
  {-# INLINE catch #-}

liftMask
  :: (Functor m)
  => (forall c. ((forall a. m a -> m a) -> m c) -> m c)
  -> ((forall a. ValidateT e m a -> ValidateT e m a) -> ValidateT e m b) -> ValidateT e m b
liftMask :: forall (m :: * -> *) e b.
Functor m =>
(forall c. ((forall a. m a -> m a) -> m c) -> m c)
-> ((forall a. ValidateT e m a -> ValidateT e m a)
    -> ValidateT e m b)
-> ValidateT e m b
liftMask forall c. ((forall a. m a -> m a) -> m c) -> m c
maskE (forall a. ValidateT e m a -> ValidateT e m a) -> ValidateT e m b
f = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e1 ->
  forall c. ((forall a. m a -> m a) -> m c) -> m c
maskE forall a b. (a -> b) -> a -> b
$ \forall a. m a -> m a
unmask ->
    forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s e
e1 forall a b. (a -> b) -> a -> b
$ (forall a. ValidateT e m a -> ValidateT e m a) -> ValidateT e m b
f forall a b. (a -> b) -> a -> b
$ \ValidateT e m a
m ->
      forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e2 ->
        forall a. m a -> m a
unmask forall a b. (a -> b) -> a -> b
$ forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s e
e2 ValidateT e m a
m
{-# INLINE liftMask #-}

instance (MonadMask m) => MonadMask (ValidateT e m) where
  mask :: forall b.
((forall a. ValidateT e m a -> ValidateT e m a) -> ValidateT e m b)
-> ValidateT e m b
mask = forall (m :: * -> *) e b.
Functor m =>
(forall c. ((forall a. m a -> m a) -> m c) -> m c)
-> ((forall a. ValidateT e m a -> ValidateT e m a)
    -> ValidateT e m b)
-> ValidateT e m b
liftMask forall (m :: * -> *) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
mask
  uninterruptibleMask :: forall b.
((forall a. ValidateT e m a -> ValidateT e m a) -> ValidateT e m b)
-> ValidateT e m b
uninterruptibleMask = forall (m :: * -> *) e b.
Functor m =>
(forall c. ((forall a. m a -> m a) -> m c) -> m c)
-> ((forall a. ValidateT e m a -> ValidateT e m a)
    -> ValidateT e m b)
-> ValidateT e m b
liftMask forall (m :: * -> *) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
uninterruptibleMask
  generalBracket :: forall a b c.
ValidateT e m a
-> (a -> ExitCase b -> ValidateT e m c)
-> (a -> ValidateT e m b)
-> ValidateT e m (b, c)
generalBracket ValidateT e m a
m a -> ExitCase b -> ValidateT e m c
f a -> ValidateT e m b
g = forall e (m :: * -> *) a.
(forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a)
-> ValidateT e m a
ValidateT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)
generalBracket
    (forall e (m :: * -> *) a.
ValidateT e m a
-> forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
getValidateT ValidateT e m a
m)
    (\a
a ExitCase b
b -> forall e (m :: * -> *) a.
ValidateT e m a
-> forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
getValidateT forall a b. (a -> b) -> a -> b
$ a -> ExitCase b -> ValidateT e m c
f a
a ExitCase b
b)
    (\a
a -> forall e (m :: * -> *) a.
ValidateT e m a
-> forall (s :: MonoMaybeS). StateT (MonoMaybe s e) (ExceptT e m) a
getValidateT forall a b. (a -> b) -> a -> b
$ a -> ValidateT e m b
g a
a)
  {-# INLINE mask #-}
  {-# INLINE uninterruptibleMask #-}
  {-# INLINE generalBracket #-}

instance (Monad m, Semigroup e) => MonadValidate e (ValidateT e m) where
  refute :: forall a. e -> ValidateT e m a
refute e
e2 = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e1 ->
    let !e3 :: e
e3 = forall (s :: MonoMaybeS) b a.
((s ~ 'SMaybe) => b) -> (a -> b) -> MonoMaybe s a -> b
monoMaybe e
e2 (forall a. Semigroup a => a -> a -> a
<> e
e2) MonoMaybe s e
e1 in forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a b. a -> Either a b
Left e
e3)
  dispute :: e -> ValidateT e m ()
dispute e
e2 = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e1 ->
    let !e3 :: e
e3 = forall (s :: MonoMaybeS) b a.
((s ~ 'SMaybe) => b) -> (a -> b) -> MonoMaybe s a -> b
monoMaybe e
e2 (forall a. Semigroup a => a -> a -> a
<> e
e2) MonoMaybe s e
e1 in forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a b. b -> Either a b
Right (forall (s :: MonoMaybeS) a. a -> MonoMaybe s a
MJust e
e3, ()))
  tolerate :: forall a. ValidateT e m a -> ValidateT e m (Maybe a)
tolerate ValidateT e m a
m = forall e (m :: * -> *) a.
Functor m =>
(forall (s :: MonoMaybeS).
 MonoMaybe s e -> m (Either e (MonoMaybe s e, a)))
-> ValidateT e m a
validateT forall a b. (a -> b) -> a -> b
$ \MonoMaybe s e
e1 ->
    forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\e
e2 -> (forall (s :: MonoMaybeS) a. a -> MonoMaybe s a
MJust e
e2, forall a. Maybe a
Nothing)) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT MonoMaybe s e
e1 ValidateT e m a
m
  {-# INLINABLE refute #-}
  {-# INLINABLE dispute #-}
  {-# INLINABLE tolerate #-}

-- | Runs a 'ValidateT' computation, returning the errors raised by 'refute' or 'dispute' if any,
-- otherwise returning the computation’s result.
runValidateT :: forall e m a. (Functor m) => ValidateT e m a -> m (Either e a)
runValidateT :: forall e (m :: * -> *) a.
Functor m =>
ValidateT e m a -> m (Either e a)
runValidateT ValidateT e m a
m = forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT forall a. MonoMaybe 'SMaybe a
MNothing ValidateT e m a
m forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
  Left e
e              -> forall a b. a -> Either a b
Left e
e
  Right (MJust e
e, a
_)  -> forall a b. a -> Either a b
Left e
e
  Right (MonoMaybe 'SMaybe e
MNothing, a
v) -> forall a b. b -> Either a b
Right a
v

-- | Runs a 'ValidateT' computation, returning the errors on failure or 'mempty' on success. The
-- computation’s result, if any, is discarded.
--
-- @
-- >>> 'execValidate' ('refute' ["bang"])
-- ["bang"]
-- >>> 'execValidate' @[] ('pure' 42)
-- []
-- @
execValidateT :: forall e m a. (Monoid e, Functor m) => ValidateT e m a -> m e
execValidateT :: forall e (m :: * -> *) a.
(Monoid e, Functor m) =>
ValidateT e m a -> m e
execValidateT = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall a. a -> a
id forall a. Monoid a => a
mempty) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e (m :: * -> *) a.
Functor m =>
ValidateT e m a -> m (Either e a)
runValidateT

{-| Runs a 'ValidateT' transformer by interpreting it in an underlying transformer with a
'MonadValidate' instance. That might seem like a strange thing to do, but it can be useful in
combination with 'mapErrors' to locally alter the error type in a larger 'ValidateT' computation.
For example:

@
throwsIntegers :: 'MonadValidate' ['Integer'] m => m ()
throwsIntegers = 'dispute' [42]

throwsBools :: 'MonadValidate' ['Bool'] m => m ()
throwsBools = 'dispute' ['False']

throwsBoth :: 'MonadValidate' ['Either' 'Integer' 'Bool'] m => m ()
throwsBoth = do
  'embedValidateT' '$' 'mapErrors' ('map' 'Left') throwsIntegers
  'embedValidateT' '$' 'mapErrors' ('map' 'Right') throwsBools

>>> 'runValidate' throwsBoth
'Left' ['Left' 42, 'Right' False]
@

@since 1.1.0.0 -}
embedValidateT :: forall e m a. (MonadValidate e m) => ValidateT e m a -> m a
embedValidateT :: forall e (m :: * -> *) a.
MonadValidate e m =>
ValidateT e m a -> m a
embedValidateT ValidateT e m a
m = forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT forall a. MonoMaybe 'SMaybe a
MNothing ValidateT e m a
m forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Left e
e              -> forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute e
e
  Right (MJust e
e, a
v)  -> forall e (m :: * -> *). MonadValidate e m => e -> m ()
dispute e
e forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> a
v
  Right (MonoMaybe 'SMaybe e
MNothing, a
v) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure a
v

-- | Applies a function to all validation errors produced by a 'ValidateT' computation.
--
-- @
-- >>> 'runValidate' '$' 'mapErrors' ('map' 'show') ('refute' [11, 42])
-- 'Left' ["11", "42"]
-- @
--
-- @since 1.1.0.0
mapErrors
  :: forall e1 e2 m a. (Monad m, Semigroup e2)
  => (e1 -> e2) -> ValidateT e1 m a -> ValidateT e2 m a
mapErrors :: forall e1 e2 (m :: * -> *) a.
(Monad m, Semigroup e2) =>
(e1 -> e2) -> ValidateT e1 m a -> ValidateT e2 m a
mapErrors e1 -> e2
f ValidateT e1 m a
m = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (s :: MonoMaybeS) e (m :: * -> *) a.
Functor m =>
MonoMaybe s e -> ValidateT e m a -> m (Either e (MonoMaybe s e, a))
unValidateT forall a. MonoMaybe 'SMaybe a
MNothing ValidateT e1 m a
m) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Left e1
e              -> forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (e1 -> e2
f e1
e)
  Right (MJust e1
e, a
v)  -> forall e (m :: * -> *). MonadValidate e m => e -> m ()
dispute (e1 -> e2
f e1
e) forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> a
v
  Right (MonoMaybe 'SMaybe e1
MNothing, a
v) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure a
v

{-| Runs a 'ValidateT' computation, and if it raised any errors, re-raises them using 'throwError'.
This effectively converts a computation that uses 'ValidateT' (or 'MonadValidate') into one that
uses 'MonadError'.

@
>>> 'runExcept' '$' 'validateToError' ('pure' 42)
'Right' 42
>>> 'runExcept' '$' 'validateToError' ('refute' ["boom"] *> 'refute' ["bang"])
'Left' ["boom", "bang"]
@

@since 1.2.0.0 -}
validateToError :: forall e m a. (MonadError e m) => ValidateT e m a -> m a
validateToError :: forall e (m :: * -> *) a. MonadError e m => ValidateT e m a -> m a
validateToError = forall e1 e2 (m :: * -> *) a.
MonadError e2 m =>
(e1 -> e2) -> ValidateT e1 m a -> m a
validateToErrorWith forall a. a -> a
id
{-# INLINE validateToError #-}

{-| Like 'validateToError', but additionally accepts a function, which is applied to the errors
raised by 'ValidateT' before passing them to 'throwError'. This can be useful to concatenate
multiple errors into one.

@
>>> 'runExcept' '$' 'validateToErrorWith' 'mconcat' ('pure' 42)
'Right' 42
>>> 'runExcept' '$' 'validateToErrorWith' 'mconcat' ('refute' ["boom"] *> 'refute' ["bang"])
'Left' "boombang"
@

@since 1.2.0.0 -}
validateToErrorWith :: forall e1 e2 m a. (MonadError e2 m) => (e1 -> e2) -> ValidateT e1 m a -> m a
validateToErrorWith :: forall e1 e2 (m :: * -> *) a.
MonadError e2 m =>
(e1 -> e2) -> ValidateT e1 m a -> m a
validateToErrorWith e1 -> e2
f = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall b c a. (b -> c) -> (a -> b) -> a -> c
. e1 -> e2
f) forall (f :: * -> *) a. Applicative f => a -> f a
pure forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall e (m :: * -> *) a.
Functor m =>
ValidateT e m a -> m (Either e a)
runValidateT
{-# INLINE validateToErrorWith #-}

-- | 'ValidateT' specialized to the 'Identity' base monad. See 'ValidateT' for usage information.
type Validate e = ValidateT e Identity

-- | See 'runValidateT'.
runValidate :: forall e a. Validate e a -> Either e a
runValidate :: forall e a. Validate e a -> Either e a
runValidate = forall a. Identity a -> a
runIdentity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e (m :: * -> *) a.
Functor m =>
ValidateT e m a -> m (Either e a)
runValidateT
{-# INLINE runValidate #-}

-- | See 'execValidateT'.
execValidate :: forall e a. (Monoid e) => Validate e a -> e
execValidate :: forall e a. Monoid e => Validate e a -> e
execValidate = forall a. Identity a -> a
runIdentity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e (m :: * -> *) a.
(Monoid e, Functor m) =>
ValidateT e m a -> m e
execValidateT
{-# INLINE execValidate #-}

{-| Monotonically increasing 'Maybe' values. A function with the type

@
forall s. 'MonoMaybe' s Foo -> 'MonoMaybe' s Bar
@

may return 'MNothing' only when given 'MNothing', but it may return 'MJust' for any input. This
is useful for keeping track of the error state within 'ValidateT', since we want to statically
prevent the possibility of a 'ValidateT' action being passed a nonempty set of errors but returning
no errors.

The benefit of this additional type tracking shows up most prominently in the implementation of
'<*>'. Consider an expression @x '<*>' y@, where @x@ is an action that fails, but @y@ is an action
that succeeds. We pass the errors returned by @x@ to @y@, then pattern-match on @y@’s result. If @y@
succeeds, we’ll end up with a tuple of type @('MonoMaybe' ''SJust' e, a)@. We can’t use the second
element of that tuple at all because we need to return a value of type @b@, but the only way to get
one is to apply a function of type @a -> b@ returned by @x@… which we don’t have, since @x@ failed.

Since we can’t produce a value of type @'Right' b@, our only option is to return a value of type
@'Left' e@. But if the first element of the tuple had type @'Maybe' e@, we’d now be in a sticky
situation! Its value could be 'Nothing', but we need it to be @'Just' e@ since we only have a
'Semigroup' instance for @e@, not a 'Monoid' instance, so we can’t produce an @e@ out of thin air.
However, by returning a 'MonoMaybe', we guarantee that the result will be @'MJust' e@, and we can
proceed safely.
-}
data MonoMaybe s a where
  MNothing :: MonoMaybe 'SMaybe a
  MJust :: forall s a. !a -> MonoMaybe s a
deriving instance (Show a) => Show (MonoMaybe s a)
deriving instance (Eq a) => Eq (MonoMaybe s a)
deriving instance (Ord a) => Ord (MonoMaybe s a)
deriving instance Functor (MonoMaybe s)

-- | The kind of types used to track the current state of a 'MonoMaybe' value.
data MonoMaybeS = SMaybe | SJust

-- | Like 'maybe' but for 'MonoMaybe'.
monoMaybe :: (s ~ 'SMaybe => b) -> (a -> b) -> MonoMaybe s a -> b
monoMaybe :: forall (s :: MonoMaybeS) b a.
((s ~ 'SMaybe) => b) -> (a -> b) -> MonoMaybe s a -> b
monoMaybe (s ~ 'SMaybe) => b
v a -> b
f = \case
  MonoMaybe s a
MNothing -> (s ~ 'SMaybe) => b
v
  MJust a
x  -> a -> b
f a
x
{-# INLINE monoMaybe #-}