{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-} -- {-# OPTIONS_GHC -fno-warn-orphans #-} import Data.Monoid import Data.Typeable import Numeric.Sum import Test.Tasty import Test.Tasty.QuickCheck import Data.Monoid.Statistics data T a = T p_memptyIsNeutral :: forall m. (Monoid m, Arbitrary m, Show m, Eq m) => T m -> TestTree p_memptyIsNeutral _ = testProperty "mempty is neutral" $ \(m :: m) -> (m <> mempty) == m && (mempty <> m) == m p_associativity :: forall m. (Monoid m, Arbitrary m, Show m, Eq m) => T m -> TestTree p_associativity _ = testProperty "associativity" $ \(a :: m) b c -> let val1 = (a <> b) <> c val2 = a <> (b <> c) in counterexample ("left : " ++ show val1) $ counterexample ("right: " ++ show val2) $ val1 == val2 p_commutativity :: forall m. (Monoid m, Arbitrary m, Show m, Eq m) => T m -> TestTree p_commutativity _ = testProperty "commutativity" $ \(a :: m) b -> (a <> b) == (b <> a) p_addValue1 :: forall a m. ( StatMonoid m a , Arbitrary m, Show m, Eq m , Arbitrary a, Show a, Eq a) => T a -> T m -> TestTree p_addValue1 _ _ = testProperty "addValue x mempty == singletonMonoid" $ \(a :: a) -> singletonMonoid a == addValue (mempty :: m) a p_addValue2 :: forall a m. ( StatMonoid m a , Arbitrary m, Show m, Eq m , Arbitrary a, Show a, Eq a) => T a -> T m -> TestTree p_addValue2 _ _ = testProperty "addValue law" $ \(x :: a) (y :: a) -> let val1 = addValue (addValue mempty y) x val2 = (addValue mempty x <> addValue (mempty :: m) y) in counterexample ("left : " ++ show val1) $ counterexample ("right: " ++ show val2) $ val1 == val2 ---------------------------------------------------------------- testType :: forall m. Typeable m => T m -> [T m -> TestTree] -> TestTree testType t props = testGroup (show (typeRep (Proxy :: Proxy m))) (fmap ($ t) props) main :: IO () main = defaultMain $ testGroup "monoid-statistics" [ testType (T :: T (CountG Int)) [ p_memptyIsNeutral , p_associativity , p_commutativity , p_addValue1 (T :: T Int) , p_addValue2 (T :: T Int) ] , testType (T :: T (Min Int)) [ p_memptyIsNeutral , p_associativity , p_commutativity , p_addValue1 (T :: T Int) , p_addValue2 (T :: T Int) ] , testType (T :: T (Max Int)) [ p_memptyIsNeutral , p_associativity , p_commutativity , p_addValue1 (T :: T Int) , p_addValue2 (T :: T Int) ] , testType (T :: T MinD) [ p_memptyIsNeutral , p_associativity , p_commutativity , p_addValue1 (T :: T Double) , p_addValue2 (T :: T Double) ] , testType (T :: T MaxD) [ p_memptyIsNeutral , p_associativity , p_commutativity , p_addValue1 (T :: T Double) , p_addValue2 (T :: T Double) ] , testType (T :: T BinomAcc) [ p_memptyIsNeutral , p_associativity , p_commutativity , p_addValue1 (T :: T Bool) , p_addValue2 (T :: T Bool) ] , testType (T :: T WelfordMean) [ p_memptyIsNeutral -- , p_associativity , p_commutativity , p_addValue1 (T :: T Double) -- , p_addValue2 (T :: T Double) ] , testType (T :: T MeanKBN) [ p_memptyIsNeutral -- , p_associativity -- , p_commutativity , p_addValue1 (T :: T Double) , p_addValue2 (T :: T Double) ] , testType (T :: T MeanKahan) [ p_memptyIsNeutral -- , p_associativity -- , p_commutativity , p_addValue1 (T :: T Double) -- , p_addValue2 (T :: T Double) ] , testType (T :: T Variance) [ p_memptyIsNeutral -- , p_associativity , p_commutativity , p_addValue1 (T :: T Double) , p_addValue2 (T :: T Double) ] ] ---------------------------------------------------------------- instance (Arbitrary a, Num a, Ord a) => Arbitrary (CountG a) where arbitrary = do NonNegative n <- arbitrary return (CountG n) instance (Arbitrary a) => Arbitrary (Max a) where arbitrary = Max <$> arbitrary instance (Arbitrary a) => Arbitrary (Min a) where arbitrary = Min <$> arbitrary instance Arbitrary MinD where arbitrary = frequency [ (1, pure mempty) , (4, MinD <$> arbitrary) ] instance Arbitrary MaxD where arbitrary = frequency [ (1, pure mempty) , (4, MaxD <$> arbitrary) ] instance Arbitrary BinomAcc where arbitrary = do NonNegative nSucc <- arbitrary NonNegative nFail <- arbitrary return $ BinomAcc nSucc (nFail + nSucc) instance Arbitrary WelfordMean where arbitrary = arbitrary >>= \case NonNegative 0 -> return mempty NonNegative n -> do m <- arbitrary return (WelfordMean n m) instance Arbitrary Variance where arbitrary = arbitrary >>= \case NonNegative 0 -> return mempty NonNegative n -> do m <- arbitrary NonNegative s <- arbitrary return $ Variance n m s instance Arbitrary MeanKBN where arbitrary = arbitrary >>= \case NonNegative 0 -> return mempty NonNegative n -> do x1 <- arbitrary x2 <- arbitrary x3 <- arbitrary return $ MeanKBN n (((zero `add` x1) `add` x2) `add` x3) instance Arbitrary MeanKahan where arbitrary = arbitrary >>= \case NonNegative 0 -> return mempty NonNegative n -> do x1 <- arbitrary x2 <- arbitrary x3 <- arbitrary return $ MeanKahan n (((zero `add` x1) `add` x2) `add` x3)