{-# LANGUAGE TemplateHaskell #-} module Main (main) where import Hedgehog import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range import Hedgehog.Checkers import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Function import Data.Monoid.Diff import Data.Monoid.Odd import Data.Semigroup newtype FreeAbelian a = FreeAbelian { getFreeAbelian :: Map a Int } deriving (Eq, Ord, Show) instance Ord a => Semigroup (FreeAbelian a) where FreeAbelian xs <> FreeAbelian ys = FreeAbelian (Map.unionWith (+) xs ys) instance Ord a => Monoid (FreeAbelian a) where mempty = FreeAbelian Map.empty mappend = (<>) freeAbelian :: MonadGen m => m (FreeAbelian Int) freeAbelian = FreeAbelian <$> Gen.map (Range.linear 0 10) ((,) <$> Gen.int (Range.linear 1 1000) <*> Gen.int (Range.linear 1 1000)) prop_AbelianMonoid :: Property prop_AbelianMonoid = property $ monoid freeAbelian intDiff :: MonadGen m => m (Diff (Sum Int)) intDiff = ((:-:) `on` Sum) <$> Gen.int (Range.linear 0 10) <*> Gen.int (Range.linear 0 10) freeDiff :: MonadGen m => m (Diff (FreeAbelian Int)) freeDiff = (:-:) <$> freeAbelian <*> freeAbelian oddGen :: MonadGen m => m Odd oddGen = fmap Odd Gen.bool prop_DiffMonoid :: Property prop_DiffMonoid = property $ monoid intDiff prop_DiffCommutative :: Property prop_DiffCommutative = property $ commutativity (<>) intDiff prop_OddMonoid :: Property prop_OddMonoid = property $ monoid oddGen prop_OddCommutative :: Property prop_OddCommutative = property $ commutativity (<>) oddGen prop_oddSTimes :: Property prop_oddSTimes = property $ do x <- forAll oddGen n <- forAll $ Gen.int (Range.linear 0 100) stimesMonoid n x === stimes n x prop_DiffInversion :: Property prop_DiffInversion = property $ inversion (<>) mempty invert intDiff prop_OddInversion :: Property prop_OddInversion = property $ inversion (<>) mempty invert oddGen prop_FreeDiffMonoid :: Property prop_FreeDiffMonoid = property $ monoid freeDiff prop_FreeDiffCommutative :: Property prop_FreeDiffCommutative = property $ commutativity (<>) freeDiff prop_FreeDiffInversion :: Property prop_FreeDiffInversion = property $ inversion (<>) mempty invert freeDiff prop_DiffOrd :: Property prop_DiffOrd = property $ ord intDiff egte where egte (Sum x :-: Sum y) = ((:-:) `on` Sum) <$> Gen.int (Range.linear x 20) <*> Gen.int (Range.linear 0 y) inversion :: (Show a, Eq a, Monad m) => (a -> a -> a) -> a -> (a -> a) -> Gen a -> PropertyT m () inversion (<+>) i inv gen = do xs <- forAll gen xs <+> inv xs === i inv xs <+> xs === i main :: IO Bool main = checkParallel $$discover