h&XU      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK Safe-Inferred'"')*/123589:;>? monad-validate4If you have a monad transformer that implements the L class, this newtype wrapper can be used to automatically derive instances of  using the  DerivingVia GHC extension.Example: {-# LANGUAGE DerivingVia #-} newtype CustomT c m a = CustomT { runCustomT :: ... } deriving ( e) via ( (CustomT c) m) monad-validateThe class of validation monads, intended to be used to validate data structures while collecting errors along the way. In a sense,  is like a combination of  and , but it isn@t entirely like either. The two essential differences are: Unlike , raising an error using  does not always abort the entire computation@it may only abort a local part of it.Unlike  , raising an error using  still causes the computation to globally fail, it just doesn@t affect local execution.&Instances must obey the following law:  D M N  N  For a more thorough explanation, with examples, see the documentation for  . monad-validateRaises a fatal validation error. Aborts the current branch of the validation (i.e. does not return). >>>   ( ["boom"] O  ["bang"]) P ["boom"] monad-validateRaises a non-fatal validation error. The overall validation fails, and the error is recorded, but validation continues in an attempt to try and discover more errors. >>>   ( ["boom"] O  ["bang"]) P ["boom", "bang"] =If not explicitly implemented, the default implementation is M N  N  (which must behave equivalently by law), but it is sometimes possible to provide a more efficient implementation.monad-validate m behaves like m), except that any fatal errors raised by . are altered to non-fatal errors that return Q. This allows m@s result to be used for further validation if it succeeds without preventing further validation from occurring upon failure. >>>   ( ( ["boom"]) O  ["bang"]) P ["boom", "bang"] monad-validateRuns an R< computation, and if it raised an error, re-raises it using 4. This effectively converts a computation that uses R (or  ) into one that uses . >>>   S  (T 42) U 42 >>>   S  (  ["boom"]) P "boom" monad-validateLike , but additionally accepts a function, which is applied to the error raised by R before passing it to 9. This can be useful if the original error type is not a V. >>>   S  (:[]) (T 42) U 42 >>>   S  (:[]) (  "boom") P ["boom"]   Safe-Inferred'"')*/123589:;>?UBmonad-validate7The kind of types used to track the current state of a  value.monad-validateMonotonically increasing W! values. A function with the type  forall s.  s Foo ->  s Bar  may return  only when given , but it may return   for any input. This is useful for keeping track of the error state within %;, since we want to statically prevent the possibility of a % 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 X. Consider an expression x 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 ( ' 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 U b/, our only option is to return a value of type P e1. But if the first element of the tuple had type W e8, we@d now be in a sticky situation! Its value could be Q, but we need it to be Y e since we only have a V instance for e, not a Z" instance, so we can@t produce an e* out of thin air. However, by returning a ', we guarantee that the result will be   e, and we can proceed safely.!monad-validate% specialized to the [ base monad. See % for usage information."monad-validate6An opaque type used to capture the current state of a % computation, used as the \ instance for %. 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).%monad-validate%6 is a monad transformer for writing validations. Like R, % is primarily concerned with the production of errors, but it differs from R in that % 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, % is also somewhat like  , but it is not just a combination of R and  9. Specifically, it differs in the following two respects: %7 automatically collects errors from all branches of an ] expression, making it possible to write code in the same style that one would use with R and automatically get additional information for free. (This is especially true when used in combination with the  ApplicativeDo language extension.)%% provides error signaling operators,  and , which are similar to ^ and _, respectively. However, both operators combine raised errors into a single value (using an arbitrary V), 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 %The first of the above two points is by far the most interesting feature of %.. Let@s make it more concrete with an example: >>> 3 ( ["bang"] `  ["boom"]) P ["bang", "boom"] ?At first blush, the above example may lead you to believe that  is like _ from  , but it is actually more like ^. Consider its type:  ::  e m => e -> m a Note that, like ^,  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  via a-, the downstream computation will not be run: >>> let getString =  ["bang"] ` T "boom" useString a =  [a] in 3 (getString a useString) P ["bang"]  This works because although the b instance for % fails as soon as the first ? is executed (as it must due to the way the second argument of a3 depends on the result of its first argument), the ] instance runs all branches of X7 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 :: (c Env m,  [Error] m) => Value -> m QueryRequest validateQueryRequest req = withObject "request" req S o -> do qrAuth <- withKey o "auth_token" parseAuthToken ~(qrTable, info) <- withKey o "table" parseTableName qrQuery <- withKey o "query" parseQuery  info S tableInfo -> pushPath "query" S validateQuery qrTable tableInfo (atIsAdmin qrAuth) qrQuery T+ 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: >>> d  env N - S validateQueryRequest [aesonQQ| { "auth_token": 123 , "table": { "name": "users" } , "query": { "add": [ { "lit": "42" } , { "select": "points" } ]} }|] P [ 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 % (with  ApplicativeDo?) may seem magical, of course, it is not. As alluded to above, % simply provides a X 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 % is used in a monad transformer stack, what happens to side effects? And what are %@s performance characteristics? The remainder of this section discusses those topics.% and the b laws%@s ] and b< instances do not conform to a strict interpretation of the b laws, which dictate that X must be equivalent to e. For %7, this is not true if we consider @equivalent@ to mean f. However, if we accept a slightly weaker notion of equivalence, we can satisfy the laws. Specifically, we may use the definition that some ! action a! is equivalent to another action b iffif 3 a produces U x, then 3 b must produce U y where x f y (and f is the usual Haskell f),and if 3 a produces P x, then 3 b must produce P y (but x and y may be unrelated).6In other words, our definition of equivalence is like f., except that we make no guarantees about the contents+ of an error should one occur. However, we do guarantee that replacing X with e 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, % provides @best effort@ error reporting: it will never return fewer errors than an equivalent use of R, but it might return more.Using % with other monad transformers% 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 ] instances for %@s ] instance to actually collect errors from multiple branches of a computation./To understand why that might be, consider that g3 must enforce a left-to-right evaluation order for X> in order to thread the state through the computation. If the a action in an expression a X 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, R enforces a left-to-right evaluation because it aborts a computation as soon as an error is thrown. Using % with these kinds of monad transformers will cause it to effectively degrade to   over R< since it will not be able to gather any errors produced by  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 g monad transformer enforces left-to-right evaluation order, it only does this for the monad  underneath it, so although g s (% e). will not be able to collect multiple errors, % e (h s) will. Note, however, that those two types differ in other ways, too@running each to completion results in different types: i (- m) s :: (j e a, s) 3 (k m s) :: j e (a, s) That kind of difference is generally true when using monad transformers@the two combinations of R and g7 have the same types as above, for example@but because % needs to be on top of certain transformers for it to be useful, combining %: 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 ] instance. Transformers like  have instances of the shape  instance b m => ] (g s m) which notably require b instances just to implement ]! However, this is not always sufficient for distinguishing which functions or instances use X and which use a7, especially since many older libraries (which predate ]) may include b0 contraints even when they only use features of ]. The only way to be certain is to examine the implementation (or conservatively write code that is explicitly restricted to ]).(As it happens, %@s ] is actually one such @uncooperative@ instance itself: it has a b constraint in its context. It is possible to write an implementation of %" without that constraint, but its X. would necessarily leak space in the same way  @s a 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 %Although the interface to % 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 % makes: % is strict in the set of errors it accumulates, which is to say it reduces them to weak head normal form (WHNF) via l immediately upon any call to  or .Furthermore, all of %@s operations, including X , operate in constant space0. This means, for example, that evaluating m xs< will consume constant space regardless of the size of xs, not counting any space consumed purely due to the relevant n instance@s traversal of xs. Finally, % accumulates errors in a left-associative/ manner, which is to say that any uses of  or % combine the existing set of errors, e%, with the added set of errors, e', via the expression e o e'.A good rule of thumb is that %, has similar performance characteristics to  (o), while types like  Validation from the either= package tend to have similar performance characteristics to p (o). That decision has both significant advantages and significant disadvantages; the following subsections elaborate further.X takes constant space3Great care has been taken in the implementation of X5 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 () = T () ` m () in m () may continuously allocate memory until it is exhausted for types such as  Validation (from the either package), but % 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 m.8In practice, this issue matters far less for types like  Validation than it does for %, as  Validation and its cousins don@t have a b 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 %, so this implementation makes choices to avoid the potential for the leak altogether.5Errors are accumulated using strict, left-associated oA major consequence of the decision to both strictly accumulate state and maintain constant space is that %@s internal applications of o 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 V' you choose to accumulate errors in is [a]!(To make it painfully explicit why using [a]4 can come back to bite you, consider that each time % executes  e'+, given some existing collection of errors e, it (strictly) evalutes e o e' to obtain a new collection of errors. Now consider the implications of that if e! is a ten thousand element list: o 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  [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. -monad-validateRuns a %- computation, returning the errors raised by  or 7 if any, otherwise returning the computation@s result..monad-validateRuns a %1 computation, returning the errors on failure or q= on success. The computation@s result, if any, is discarded. >>> 4 ( ["bang"]) ["bang"] >>> 4 @[] (T 42) [] /monad-validateRuns a % transformer by interpreting it in an underlying transformer with a  instance. That might seem like a strange thing to do, but it can be useful in combination with 0- to locally alter the error type in a larger % computation. For example: throwsIntegers ::  [r] m => m () throwsIntegers =  [42] throwsBools ::  [s] m => m () throwsBools =  [t] throwsBoth ::  [j r s] m => m () throwsBoth = do / S 0 (u P) throwsIntegers / S 0 (u U) throwsBools >>> 3 throwsBoth P [P 42, U False] 0monad-validate:Applies a function to all validation errors produced by a % computation. >>> 3 S 0 (u v) ( [11, 42]) P ["11", "42"] 1monad-validateRuns a % computation, and if it raised any errors, re-raises them using ^4. This effectively converts a computation that uses % (or ) into one that uses w. >>> x S 1 (T 42) U 42 >>> x S 1 ( ["boom"] *>  ["bang"]) P ["boom", "bang"] 2monad-validateLike 1, but additionally accepts a function, which is applied to the errors raised by % before passing them to ^=. This can be useful to concatenate multiple errors into one. >>> x S 2 y (T 42) U 42 >>> x S 2 y ( ["boom"] *>  ["bang"]) P "boombang" 3monad-validateSee -.4monad-validateSee ..5monad-validateLike z but for . !"$#%'&()*+,-./012345%'&()"$#*+,-./012!34 5 Safe-Inferred&"')*/123589:;>?U!%-./01234%-./012!34 !"#$%&'()*+,-./0123456789::;  <=>?@ABCDEFG HIJKLMNOPQRSTUVWXYZ[\]^_`abcdecfgcfhcijcklmnocfpcfqcircfscktcfuckvcfwcxy`azcf{|| cf}cf~cf|cfcfmmmcimcccfccfcfc|mncfc-monad-validate-1.2.0.2-GphXJn2VORS8tg8yImMY5LControl.Monad.Validate.ClassControl.Monad.ValidateControl.Monad.Validate.InternalControl.Monad.Error.Class MonadErrorControl.Monad.Writer.Class MonadWriter throwErrortell ValidateT runValidateControl.Monad.ExceptControl.Monad.WriterWriterT Data.Foldablefor_Control.Monad.Reader runReaderControl.Monad.StateStateTfoldl'Data.SemigroupDualWrappedMonadTransWrapMonadTransunwrapMonadTrans MonadValidaterefutedisputetolerateexceptToValidateexceptToValidateWith$fMonadValidateeRWST$fMonadValidateeWriterT!$fMonadValidateeWrappedMonadTrans$fFunctorWrappedMonadTrans$fApplicativeWrappedMonadTrans$fMonadWrappedMonadTrans$fMonadTransWrappedMonadTrans$$fMonadTransControlWrappedMonadTrans$fMonadValidateeWriterT0$fMonadValidateeWriterT1$fMonadValidateeStateT$fMonadValidateeStateT0$fMonadValidateeRWST0$fMonadValidateeRWST1$fMonadValidateeReaderT$fMonadValidateeMaybeT$fMonadValidateeExceptT$fMonadValidateeIdentityT MonoMaybeSSMaybeSJust MonoMaybeMNothingMJustValidateValidateTStategetValidateTState getValidateT validateT unValidateTinvalidRestoreError liftCatchliftMask runValidateT execValidateTembedValidateT mapErrorsvalidateToErrorvalidateToErrorWith execValidate monoMaybe$fMonadValidateeValidateT$fMonadMaskValidateT$fMonadCatchValidateT$fMonadThrowValidateT$fMonadWriterwValidateT$fMonadStatesValidateT$fMonadReaderrValidateT$fMonadErroreValidateT$fMonadBaseControlbValidateT$fMonadTransControlValidateT$fMonadBasebValidateT$fMonadIOValidateT$fMonadTransValidateT$fMonadValidateT$fApplicativeValidateT$fFunctorMonoMaybe$fOrdMonoMaybe $fEqMonoMaybe$fShowMonoMaybe$fFunctorValidateTState$fShowValidateTState$fFunctorValidateT,monad-control-1.0.3.1-8cTxnktplxILi7bGYZXxIVControl.Monad.Trans.ControlMonadTransControlbase Data.FunctorvoidGHC.Base.>> Data.EitherLeft GHC.MaybeNothingtransformers-0.5.6.2Control.Monad.Trans.ExceptExceptT$pureRight SemigroupMaybe<*>JustMonoidData.Functor.IdentityIdentityStT Applicative mtl-2.2.2*>>>=MonadControl.Monad.Reader.Class MonadReaderflipapghc-prim GHC.Classes== Control.Monad.Trans.State.StrictStaterunStateEither runStateTGHC.Primseq sequence_Foldable<>foldrmempty ghc-bignumGHC.Num.IntegerInteger GHC.TypesBoolFalsemapGHC.Showshow runExceptmconcat Data.Maybemaybe