0 | module Control.Validation
12 | import Control.Monad.Identity
13 | import Control.Monad.Error.Either
17 | import Decidable.Equality
23 | Result : (Type -> Type) -> Type -> Type
24 | Result m = EitherT String m
31 | data ValidatorT : (Type -> Type) -> Type -> Type -> Type where
32 | MkValidator : (a -> Result m b) -> ValidatorT m a b
39 | data PropValidator : (Type -> Type) -> (t : Type) -> (t -> Type) -> Type where
40 | MkPropValidator : ((x : t) -> Result m (p x)) -> PropValidator m t p
43 | Validator : Type -> Type -> Type
44 | Validator = ValidatorT Identity
50 | validateT : ValidatorT m a b -> a -> Result m b
51 | validateT (MkValidator v) = v
55 | validate : Validator a b -> a -> Either String b
56 | validate v = runIdentity . runEitherT . validateT v
60 | validator : (a -> Result m b) -> ValidatorT m a b
61 | validator = MkValidator
64 | Functor m => Functor (ValidatorT m a) where
65 | map f v = MkValidator (map f . validateT v)
68 | Monad m => Applicative (ValidatorT m a) where
69 | pure a = MkValidator (const $
pure a)
70 | f <*> a = MkValidator (\x => validateT f x <*> validateT a x)
73 | Monad m => Monad (ValidatorT m a) where
74 | v >>= f = MkValidator $
\x => do
82 | prop : PropValidator m t p -> (x : t) -> ValidatorT m a (p x)
83 | prop (MkPropValidator v) x = MkValidator (const $
v x)
85 | replaceError : Monad m => String -> Result m a -> Result m a
86 | replaceError e = bimapEitherT (const e) id
90 | withError : Monad m => String -> ValidatorT m a b -> ValidatorT m a b
91 | withError e (MkValidator f) = MkValidator (replaceError e . f)
95 | fail : Applicative m => String -> ValidatorT m a b
96 | fail s = MkValidator $
\_ => left s
102 | (>>>) : Monad m => ValidatorT m a b -> ValidatorT m b c -> ValidatorT m a c
103 | left >>> right = MkValidator (validateT left >=> validateT right)
105 | Monad m => Alternative (ValidatorT m a) where
106 | left <|> right = MkValidator $
\x => MkEitherT $
do
107 | case !(runEitherT $
validateT left x) of
108 | (Right r) => pure $
Right r
109 | (Left e) => case !(runEitherT $
validateT right x) of
110 | (Right r) => pure $
Right r
111 | (Left e') => pure $
Left (e <+> " / " <+> e')
113 | empty = MkValidator $
\x => MkEitherT $
pure (Left "invalid")
117 | contramap : (a -> b) -> ValidatorT m b c -> ValidatorT m a c
118 | contramap f v = MkValidator (validateT v . f)
125 | decide : Monad m => (t -> String) -> ((x : t) -> Dec (p x)) -> PropValidator m t p
126 | decide msg dec = MkPropValidator $
\x => case dec x of
127 | Yes prf => pure prf
128 | No _ => left (msg x)
133 | fromMaybe : Monad m => (a -> String) -> (a -> Maybe b) -> ValidatorT m a b
134 | fromMaybe e f = MkValidator $
\a => case f a of
135 | Nothing => left $
e a
140 | natural : Monad m => ValidatorT m String Nat
141 | natural = fromMaybe mkError parsePositive
143 | mkError : String -> String
144 | mkError s = "'" <+> s <+> "' is not a natural number."
148 | integral : Num a => Neg a => Monad m => ValidatorT m String a
149 | integral = fromMaybe mkError parseInteger
151 | mkError : String -> String
152 | mkError s = "'" <+> s <+> "' is not an integer."
156 | double : Monad m => ValidatorT m String Double
157 | double = fromMaybe mkError parseDouble
159 | mkError : String -> String
160 | mkError s = "'" <+> s <+> "is not a decimal."
165 | length : Monad m => (l : Nat) -> ValidatorT m (List a) (Vect l a)
166 | length l = MkValidator (validateVector l)
168 | validateVector : (l : Nat) -> List a -> Result m (Vect l a)
169 | validateVector Z [] = pure []
170 | validateVector (S _) [] = left "Missing list element."
171 | validateVector Z (_ :: _) = left "Excessive list element."
172 | validateVector (S k) (x :: xs) = do
173 | ys <- validateVector k xs
178 | equal : Monad m => DecEq t => (a : t) -> PropValidator m t (\b => a = b)
179 | equal a = MkPropValidator $
\b => case decEq a b of
180 | Yes prf => pure prf
181 | No _ => left "Values are not equal."
185 | lteNat : Monad m => (bound : Nat) -> PropValidator m Nat (flip LTE bound)
186 | lteNat bound = decide
187 | (\n => show n <+> " is not lower or equal to " <+> show bound)
188 | (\n => isLTE n bound)
192 | gteNat : Monad m => (bound : Nat) -> PropValidator m Nat (flip GTE bound)
193 | gteNat bound = decide
194 | (\n => show n <+> " is not greater or equal to " <+> show bound)
199 | ltNat : Monad m => (bound : Nat) -> PropValidator m Nat (flip LT bound)
200 | ltNat bound = decide
201 | (\n => show n <+> " is not strictly lower than " <+> show bound)
202 | (\n => isLTE (S n) bound)
206 | gtNat : Monad m => (bound : Nat) -> PropValidator m Nat (flip GT bound)
207 | gtNat bound = decide
208 | (\n => show n <+> " is not strictly greater than " <+> show bound)