hedgehog-checkers-0.1.0.0: src/Hedgehog/Checkers/Classes.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
module Hedgehog.Checkers.Classes
(
-- | Classes
ord
, alt
, alternative
, alternativeAltAgreement
, bifunctor
, functor
, semigroup
, monoid
, apply
, applicative
, applicativeApplyAgreement
) where
import Control.Applicative
import Data.Bifunctor
import Data.Functor.Alt
import Data.Semigroup
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Hedgehog.Checkers.Properties
import Hedgehog.Checkers.Ugly.Function.Hack
-- | Total ordering, genf (a -> Gen a) should
-- always return a value equal to or higher
-- than its input.
ord :: forall a. (Eq a, Ord a, Show a)
=> Gen a -> (a -> Gen a) -> PropertyT IO ()
ord gena genf = do
reflexive rel gena
transitive rel gena genf
antiSymmetric rel gena genf
where
rel = (<=)
-- | <!> is associative: (a <!> b) <!> c = a <!> (b <!> c)
-- <$> left-distributes over <!>: f <$> (a <!> b) = (f <$> a) <!> (f <$> b)
alt :: ( Alt f
, Eq (f a)
, Show (f a)
)
=> Gen (f a) -> PropertyT IO ()
alt gen = do
associativity (<!>) gen
-- f <$> (a <!> b) = (f <$> a) <!> (f <$> b)
-- | Alternative instances should respect identity
-- (left and right) and associativity for (<|>)
-- empty <|> x = x
-- x <|> empty = x
--
-- a <|> (b <|> c) = (a <|> b) <|> c
alternative :: ( Alternative f
, Eq (f a)
, Show (f a)
)
=> Gen (f a) -> PropertyT IO ()
alternative gen = do
identity (<|>) empty gen
associativity (<|>) gen
alternativeAltAgreement :: ( Alt f
, Alternative f
, Eq (f a)
, Show (f a)
)
=> Gen (f a) -> PropertyT IO ()
alternativeAltAgreement gen = do
fa <- forAll gen
fb <- forAll gen
(fa <!> fb) === (fa <|> fb)
-- fmap (f . g) == fmap f . fmap g
-- ??? inferrable from: fmap id = id
functor :: ( Functor f
, Eq (f a)
, Show (f a)
)
=> Gen (f a) -> PropertyT IO ()
functor gen = do
functorIdentity
where functorIdentity = do
fa <- forAll gen
fmap id fa === id fa
-- bimap id id ≡ id
-- first id ≡ id
-- second id ≡ id
-- bimap f g ≡ first f . second g
bifunctor :: -- forall f a b .
( Bifunctor f
, Eq (f a b)
, Eq (f c c)
, Ord a
, Ord b
, Show (f a b)
, Show (f c c)
)
=> Gen (f a b)
-> Gen a
-> Gen b
-> Gen c
-> PropertyT IO ()
bifunctor gen gena genb genc = do
bimapIdentity
firstIdentity
secondIdentity
bimapFirstSecondDistribute
where bimapIdentity = do
fab <- forAll gen
bimap id id fab === id fab
firstIdentity = do
fab <- forAll gen
first id fab === id fab
secondIdentity = do
fab <- forAll gen
second id fab === id fab
bimapFirstSecondDistribute = do
fab <- forAll gen
f <- ordFuncWtf gena genc
g <- ordFuncWtf genb genc
bimap f g fab === (first f . second g) fab
semigroup :: ( Semigroup a
, Eq a
, Show a
)
=> Gen a
-> PropertyT IO ()
semigroup gen = do
associativity (<>) gen
monoid :: ( Monoid a
, Semigroup a
, Eq a
, Show a
)
=> Gen a
-> PropertyT IO ()
monoid gen = do
semigroup gen
identity mappend mempty gen
associativity mappend gen
monoidSemigroupSame
where monoidSemigroupSame = do
a <- forAll gen
b <- forAll gen
mappend a b === a <> b
apply :: forall f a b c
. ( Apply f
, Eq (f a)
, Eq (f b)
, Eq (f c)
, Ord a
, Ord b
, Show a
, Show b
, Show c
, Show (f a)
, Show (f b)
, Show (f c)
)
=> Gen (f a)
-> Gen a
-> Gen b
-> Gen c
-> PropertyT IO ()
apply gen gena genb genc = do
applyComposition
applyRight
applyLeft
where applyComposition = do
fa <- forAll gen
fbc <- liftedFunctionWtf gen genb genc
fab <- liftedFunctionWtf gen gena genb
((.) <$> fbc <.> fab <.> fa) === (fbc <.> (fab <.> fa))
applyRight = do
fa <- forAll gen
fbc <- liftedFunctionWtf gen genb genc
ab <- ordFuncWtf gena genb
(fbc <.> (ab <$> fa)) === ((. ab) <$> fbc <.> fa)
applyLeft = do
fa <- forAll gen
fab <- liftedFunctionWtf gen gena genb
bc <- ordFuncWtf genb genc
(bc <$> (fab <.> fa)) === ((bc .) <$> fab <.> fa)
applicative :: forall f a b c
. ( Applicative f
, Eq (f a)
, Eq (f b)
, Eq (f c)
, Ord a
, Ord b
, Show a
, Show (f a)
, Show (f b)
, Show (f c)
)
=> Gen (f a)
-> Gen a
-> Gen b
-> Gen c
-> PropertyT IO ()
applicative gen gena genb genc = do
applicativeIdentity
applicativeComposition
applicativeHomomorphism
applicativeInterchange
applicativeFunctor
where applicativeIdentity = do
fa <- forAll gen
(pure id <*> fa) === fa
applicativeComposition = do
fa <- forAll gen
fbc <- liftedFunctionWtf gen genb genc
fab <- liftedFunctionWtf gen gena genb
(pure (.) <*> fbc <*> fab <*> fa) === (fbc <*> (fab <*> fa))
applicativeHomomorphism = do
a <- forAll gena
f <- ordFuncWtf gena genb
let p :: x -> f x
p = pure
(p f <*> p a) === p (f a)
applicativeInterchange = do
a <- forAll gena
fab <- liftedFunctionWtf gen gena genb
(fab <*> pure a) === (pure ($ a) <*> fab)
applicativeFunctor = do
fa <- forAll gen
f <- ordFuncWtf gena genb
fmap f fa === (pure f <*> fa)
applicativeApplyAgreement :: ( Monad m
, Apply f
, Applicative f
, Show b
, Show (f a)
, Show (f b)
, Eq (f b)
, Ord a
)
=> Gen (f a) -> Gen a -> Gen b -> PropertyT m ()
applicativeApplyAgreement gen gena genb = do
fa <- forAll gen
fab <- liftedFunctionWtf gen gena genb
(fab <.> fa) === (fab <*> fa)
---- Done
-- (Semigroup e, Monoid e) => Alternative (Validation e)
-- Alt (Validation e)
-- Functor (Validation e)
-- Bifunctor Validation
-- Semigroup e => Semigroup (Validation e a)
-- Monoid e => Monoid (Validation e a)Source
-- Semigroup e => Applicative (Validation e)
-- (Ord a, Ord e) => Ord (Validation e a)
---- To be done
-- Traversable (Validation e)
-- Bitraversable Validation
-- (Eq a, Eq e) => Eq (Validation e a)
-- (Show a, Show e) => Show (Validation e a)