ClassLaws-0.3.0.0: src/Data/Monoid/Laws/Instances.hs
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverlappingInstances #-}
-- | Conctrete tests of some instances od the 'Monoid' laws (for
-- 'Endo', mainly). The laws themselves are one level up in the module
-- hierarchy: 'Data.Monoid.Laws.defaultMonoidLaw1' etc.
module Data.Monoid.Laws.Instances where
import Data.Monoid (Monoid(mappend, mempty), Endo(Endo), appEndo)
import Data.Monoid.Laws (MonoidLaws(..), MonoidLaw1, MonoidLaw2, MonoidLaw3)
import Test.ClassLaws ( Equal, Law, quickLawCheck, lawtest, Property, quickCheck
, Partial(Partial), unPartial
, ArbitraryPartial(arbitraryPartial), SemanticEq((==!), semanticEq), SemanticOrd
, quickLawCheckPartial
)
import Test.ClassLaws.TestingDatatypes (MyList(..), (+++))
import Test.ClassLaws.TestingFinFuns(arbitraryPartialFun, showPartialFun, eqPartial, semEqFun)
import Control.Monad (liftM)
import Data.List(intersperse)
instance MonoidLaws (Endo a)
-- | Cheating: just showing a few values (@map f [0..10]@).
instance Show (Endo Int) where
show (Endo f) = "E("++(concat $ intersperse "," $ map (show . f) [0..10])++")"
testMonoidEndo =
do quickLawCheck (undefined::MonoidLaw1 (Endo Bool))
quickLawCheck (undefined::MonoidLaw2 (Endo Bool))
quickLawCheck (undefined::MonoidLaw3 (Endo Bool))
instance (Bounded a, Enum a, Show (Partial a)) => Show (Partial (Endo a)) where
show (Partial (Endo e)) = showPartialFun e
instance (Bounded a, Enum a, SemanticOrd a,
ArbitraryPartial a) => ArbitraryPartial (Endo a) where
arbitraryPartial = liftM Endo (arbitraryPartialFun arbitraryPartial)
instance (Bounded a, Enum a, Eq a) => Eq (Endo a) where
(Endo f) == (Endo g) = f == g
{-
-- Alternative definition, needs -- {-# LANGUAGE UndecidableInstances #-}
instance SemanticEq (a->a) => SemanticEq (Endo a) where
semanticEq tweak (Endo f) (Endo g) = semanticEq tweak f g
-}
instance (Bounded a, Enum a, SemanticEq a) => SemanticEq (Endo a) where
semanticEq tweak (Endo f) (Endo g) = semEqFun semanticEq tweak f g
testMonoidEndoPartial = do
quickLawCheckPartial (undefined::MonoidLaw1 (Endo Bool)) -- expected failure
quickLawCheckPartial (undefined::MonoidLaw2 (Endo Bool)) -- expected failure
quickLawCheckPartial (undefined::MonoidLaw3 (Endo Bool))
{-
The following Monoid instance for MyList does *not* satisfy the Monoid laws.
-}
instance Monoid (MyList a) where
mempty = Nil
mappend xs ys = xs +++ ys +++ xs
instance MonoidLaws (MyList a)
testMonoidMyList =
do quickLawCheck (undefined :: MonoidLaw1 (MyList Int))
quickLawCheck (undefined :: MonoidLaw2 (MyList Int))
quickLawCheck (undefined :: MonoidLaw3 (MyList Int))
main = do testMonoidEndo
testMonoidMyList -- expected failures
-- ================================================================
-- Just for fun: Endo Bool is also finite and bounded ...
instance Bounded (Endo Bool) where
minBound = Endo (const False)
maxBound = Endo (const True)
instance Enum (Endo Bool) where
fromEnum (Endo f) = 2*fromEnum (f False) + fromEnum (f True)
toEnum n = Endo (\b->if b then toEnum(n`mod`2) else toEnum (n`div`2))
-- cheating: should really check if n is within 0..3
b2i :: Bool -> Int
b2i = fromEnum
instance Show (Endo Bool) where
show (Endo f) = 'E':concatMap (show.b2i.f) [False,True]
test_roundtrip :: Bool
test_roundtrip = (toEnum :: Int -> Endo Bool) . (fromEnum :: Endo Bool -> Int) == id