verdict-0.0.0.0: src/Verdict/Class.hs
{-# LANGUAGE OverloadedStrings #-}
module Verdict.Class where
import Control.Monad
import Data.Monoid
import Data.Proxy
import qualified Data.Text as Text
import GHC.TypeLits
import Verdict.Types
------------------------------------------------------------------------------
-- * HaskVerdict
------------------------------------------------------------------------------
class HaskVerdict a b where
haskVerdict :: Proxy a -> b -> Maybe ErrorTree
------------------------------------------------------------------------------
-- * Logical Base Terms
------------------------------------------------------------------------------
instance (HaskVerdict a r, HaskVerdict b r) => HaskVerdict (a :&& b) r where
haskVerdict _ x = And <$> haskVerdict pa x <*> haskVerdict pb x
where pa = Proxy :: Proxy a
pb = Proxy :: Proxy b
instance (HaskVerdict a r, HaskVerdict b r) => HaskVerdict (a :|| b) r where
haskVerdict _ x = Or <$> haskVerdict pa x <*> haskVerdict pb x
where pa = Proxy :: Proxy a
pb = Proxy :: Proxy b
instance (HaskVerdict c a) => HaskVerdict (Not c) a where
haskVerdict _ x = case haskVerdict p x of
Just _ -> Nothing
Nothing -> Just (Leaf "this still needs to be figured out")
where p = Proxy :: Proxy c
instance HaskVerdict 'True a where
haskVerdict _ _ = Nothing
------------------------------------------------------------------------------
-- * Datatype Representation Terms
------------------------------------------------------------------------------
{-instance ( G.Generic a ) => HaskVerdict (a :* b) r where-}
{-haskVerdict _ x = foldM (G.hcollapse . G.hap r $ G.from x)-}
{-where pa = Proxy :: Proxy a-}
{-pb = Proxy :: Proxy b-}
{-v1 = G.Fn $ \(G.I n) -> G.K (haskVerdict pa n)-}
{-v2 = G.Fn $ \(G.I n) -> G.K (haskVerdict pb n)-}
{-r = (v1 G.:* v2 G.:* G.Nil) G.:* G.Nil-}
------------------------------------------------------------------------------
-- * Other Base Terms
------------------------------------------------------------------------------
instance HaskVerdict () a where
haskVerdict _ = const Nothing
instance (Ord b, Show b, KnownVal a b) => HaskVerdict (Maximum a) b where
haskVerdict _ = check (<= p) ("Should be less than " <> showT p)
where p = knownVal (Proxy :: Proxy a)
instance (Ord b, Show b, KnownVal a b) => HaskVerdict (Minimum a) b where
haskVerdict _ = check (>= p) ("Should be more than " <> showT p)
where p = knownVal (Proxy :: Proxy a)
instance (Foldable f, Show (f b), KnownNat a)
=> HaskVerdict (MaxLength a) (f b) where
haskVerdict _ = check ((<= p) . length)
("Should be of length less than " <> showT p)
where p = fromInteger $ natVal (Proxy :: Proxy a)
instance (Foldable f, Show (f b), KnownNat a)
=> HaskVerdict (MinLength a) (f b) where
haskVerdict _ = check ((>= p) . length)
("Should be of length more than " <> showT p)
where p = fromInteger $ knownVal (Proxy :: Proxy a)
instance (Foldable t, KnownNat a) => HaskVerdict (Length a) (t b) where
haskVerdict _ = check ((== p) . length) ("Should be of length " <> showT p)
where p = fromInteger $ natVal (Proxy :: Proxy a)
instance (Foldable t, Show b, Eq b, KnownVal a b)
=> HaskVerdict (HasElem a) (t b) where
haskVerdict _ = check (elem p) ("Should contain " <> showT p)
where p = knownVal (Proxy :: Proxy a)
instance (KnownNat n, Integral a) => HaskVerdict (MultipleOf n) a where
haskVerdict _ = check (\x -> (toInteger x `rem` p) == 0) ("Not a multiple of " <> showT p)
where p = natVal (Proxy :: Proxy n)
showT :: Show a => a -> Text.Text
showT = Text.pack . show
check :: (x -> Bool) -> err -> x -> Maybe (ErrorTree' err)
check pred' err x = guard (not $ pred' x) >> pure (Leaf err)
------------------------------------------------------------------------------
-- Known Val
class KnownVal a b | a -> b where
knownVal :: Proxy a -> b
instance KnownNat n => KnownVal n Integer where
knownVal = natVal