contracheck-applicative 0.1.1.0 → 0.1.2
raw patch · 4 files changed
+55/−31 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Control.Validation.Check: Unvalidated :: a -> Unvalidated (a :: Type)
+ Control.Validation.Check: MkUnvalidated :: a -> Unvalidated (a :: Type)
Files
- ChangeLog.md +2/−0
- README.md +49/−27
- contracheck-applicative.cabal +3/−3
- src/Control/Validation/Check.hs +1/−1
ChangeLog.md view
@@ -1,3 +1,5 @@ # Changelog for contracheck-applicative +## 0.1.1.1 Update documentation+ ## 0.1.1.0 Drop Checkable instances for Text and ByteString
README.md view
@@ -3,9 +3,20 @@ This package provides some simple yet useful types and functions to dynamically check properties of your data. -Why use this library?----------------------+# Table of contents+1. [Why use this library](#why)+2. [Quickstart](#quickstart)+ 1. [Types](#Types)+ * [`Unvalidated`](#Unvalidated)+ * [`CheckResult`](#CheckResult)+ * [`Check`](#Check)+ 2. [Composition of `Check`'s](#composition)+ 3. [Combination of `Check`'s](#combination)+ 4. [Dealing with additional context](#context)+ 5. [`Checkable` Typeclass](#typeclass) +# Why use this library? <a name="why"></a>+ Runtime-checking for properties of data is the poor man's parsing. Nonetheless, sometimes it has do be done, and most of the time is not really pretty. Most validation libraries define validations to be a type like `a -> Either Text a`, which makes sense as it captures the essence of validations: Put something in, and you either get it back and know your data is alright, or you have an error to work with. But the type `a -> Either Text a` does not behave nicely:@@ -16,9 +27,7 @@ This library attempts to fix these issues. -Quickstart------------+# Quickstart <a name="quickstart"></a> A `Check` is a function that takes an `Unvalidated` value and returns the result, possibly with a context: If the input has `Passed` the check or `Failed` it with a number of possible errors.@@ -33,26 +42,40 @@ type Check' e = Check e Identity ``` +## Types <a name="types"></a>+Basically all this library does is provide convenient instances for the following types. -Unvalidated-------------The `Unvalidated` newtype is to make a distinction between validated and unvalidated values on the type level. It is often convient to give an orphan instance for the typeclass of your choice via `-XStandaloneDeriving` so unvalidated data cannot get into your system, e.g.+### `Unvalidated` <a name="unvalidated"></a>+ ```haskell+newtype Unvalidated a = Unvalidated { unsafeValidate :: a } +```++The `Unvalidated` newtype is to make a distinction between validated and unvalidated values on the type level. It is often convient to give an orphan instance for the typeclass of your choice via `-XStandaloneDeriving` so unvalidated data cannot sneak into your system, e.g.+```haskell {-# language StandaloneDeriving, GeneralizedNewtypeDeriving, DerivingStrategies #-} import Data.Aeson(FromJSON) deriving newtype instance (FromJSON a) => FromJSON (Unvalidated a) ``` -CheckResult-------------It has a monoid instance so it collects all possible errors, that is, it is not lazy in its failure component.-+### `CheckResult` <a name="CheckResult"></a>+```haskell+data CheckResult + = Passed+ | Failed (Seq a)+ +instance Monoid CheckResult+instance Functor CheckResult+``` -Basically all this library does is provide convenient instances for these types.+It has a monoid instance that collects all possible errors, that is, it is not lazy in its failure component. +### Check <a name="Check"></a> -Check------+```haskell+newtype Check e m a = Check { runCheck :: Unvalidated a -> m (CheckResult e) }+type Check' e = Check e Identity+``` To start off lets give some simple examples. We construct `Check`s using the auxiliary combinators * `failsWith :: e -> CheckResult e`@@ -78,12 +101,13 @@ then Passed else failsWith invalidChars ```-There are some other combinators to construct checks in various flavours.-You can run the checks using `validateBy'` if you want to use the validated result or just by `runCheck` if you just want to know if your input passed the check (or which errors occured). -Composition------------+There are some other combinators to construct checks in various flavours, notably the `test/(?>)` family.+You can run the checks using `validateBy'` if you want to use the validated result or just by `runCheck` if you just want to know if your input passed the check (though this is slower than it needs to be as the check collects all possible errors). +## Composition of `Check`s <a name="composition"></a>++ The `Check` type is contravariant in the parameter to be checked (in fact, the whole library is merely a big wrapper around the instances for the type classes from the package [contravariant](https://www.stackage.org/package/contravariant)). This tells us that we can "pull back" checks to other types: ```haskell@@ -109,10 +133,9 @@ * `divide :: (a -> (b, c)) -> Check e m b -> Check e m c -> Check e m a` * `choose :: (a -> Either b c) -> Check e m b -> Check e m c -> Check e m a` -Combination------------+## Combination of `Check`'s <a name="combination"></a> -But now you want to combine your checks, e.g. to check a registration form. A first attempt might be to use the monoid instance of `CheckResult`. Note that it collects all errors and does not short-circuit if a `Check` fails (as you do not want to be that guy that sends the registration form back twenty times with different errors). But fortunately the `Monoid`-instance of `CheckResult` lifts to `Checks`! That means we can use the `Semigroup/Monoid` operations on `Checks`, (`mempty` being the trivial `Check` that always succeeds).+But now you want to combine your checks, e.g. to check a registration form. A first attempt might be to use the monoid instance of `CheckResult`. Note that it collects all errors and does not short-circuit if a `Check` fails (as you do not want to be _that_ guy that sends the registration form back twenty times with different errors). But fortunately the `Monoid`-instance of `CheckResult` lifts to `Checks`! That means we can use the `Semigroup/Monoid` operations on `Checks`, (`mempty` being the trivial `Check` that always succeeds). ```haskell data Registration = Registration { registrationAge :: Age@@ -125,8 +148,7 @@ <> contramap registrationEmail mempty -- of course unneccessary as it does nothing, but here for completeness ``` -Additional Context-------------------+## Dealing with additional Context <a name="context"></a> Sometimes you need to check properties, but the check itself has a sideeffect e.g. making a HTTP request or reading from a database. This is no problem, as 1. `Check`s may have a context (remember that `Check' e a ≡ Check e Identity a`, a `Check` with a trivial context).@@ -192,9 +214,9 @@ Thats about it. -Checkable typeclass--------------------There is also a typeclass in Control.Validation.Class, but it has to be used with care as it does not perform any Checks on primitive types and this is often not what you want. You should probably use it only on nested structures made up solely from custom data types.+## `Checkable` typeclass <a name="typeclass"></a>++There is also a typeclass in the module Control.Validation.Class, but it has to be used with care as it does not perform any Checks on primitive types and this is often not what you want. You should probably use it _only_ on nested structures made up solely from custom data types, and otherwise define the checks explicitly.
contracheck-applicative.cabal view
@@ -4,12 +4,12 @@ -- -- see: https://github.com/sol/hpack ----- hash: 7bcfb4f8bca1b4c9e06b625e368c40c38640e33f9dfa799987c2dd92d33689a9+-- hash: 51671db44a11779c126bbc3f411fe9d3906c8c1e0eb1b59647fd4c8b0bf139f0 name: contracheck-applicative-version: 0.1.1.0+version: 0.1.2 synopsis: Validation types/typeclass based on the contravariance.-description: This package provides types and a typeclass that allow for effectful validation and easy composition. For documentation see the [README](https://gitlab.com/Birkmann/validation-check/-/blob/master/README.md). If there are any issues, contact me at 99fabianb@sis.gl.+description: This package provides types and a typeclass that allow for effectful validation and easy composition. For documentation see the [README](https://gitlab.com/Birkmann/validation-check/-/blob/master/README.md). If there are any issues, contact me at 99fabianb@sis.gl or add an issue on [gitlab](https://gitlab.com/Birkmann/validation-check). category: Validation author: Fabian Birkmann maintainer: 99fabianb@sis.gl
src/Control/Validation/Check.hs view
@@ -214,7 +214,7 @@ -- with `check`. It is a special case of 'choose' from 'Decidable'. -- It gives an example for how 'Check's expand to other datatypes since they are -- 'Divisible' and 'Decidable', see generalizing a check to lists:--- >+-- -- > checkList :: Applicative m => Check e m a -> Check e m [a] -- > checkList c = passOnRight (\case -- > [] -> Right ()