module Main where import Test.Tasty import Data.Proxy import System.Environment import Control.Monad (ap) import Test.QuickCheck import Test.Tasty.QuickCheck.Laws main :: IO () main = do setEnv "TASTY_NUM_THREADS" "6" setEnv "TASTY_QUICKCHECK_TESTS" "1000" defaultMain $ testGroup "Laws" [ testGroup "Eq Laws" [ testEqLaws pU , testEqLaws pB , testEqLaws pI ] , testGroup "Monoid Laws" [ testMonoidLaws (Proxy :: Proxy [()]) , testMonoidLaws (Proxy :: Proxy [Bool]) , testMonoidLaws (Proxy :: Proxy (Maybe [()])) ] , testGroup "Functor Laws" [ testFunctorLaws1 pMb pU pU (const (==)) , testFunctorLaws1 pEi pU pU (const (==)) , testFunctorLaws1 pLs pU pU (const (==)) , testFunctorLaws2 pMb pU pU pB (const (==)) , testFunctorLaws2 pEi pU pU pB (const (==)) , testFunctorLaws2 pLs pU pU pB (const (==)) , testFunctorLaws3 pMb pU pU pB pI (const (==)) , testFunctorLaws3 pEi pU pU pB pI (const (==)) , testFunctorLaws3 pLs pU pU pB pI (const (==)) ] , testGroup "Applicative Laws" [ testApplicativeLaws1 pMb pU pU (const (==)) , testApplicativeLaws1 pEi pU pU (const (==)) , testApplicativeLaws1 pLs pU pU (const (==)) , testApplicativeLaws2 pMb pU pU pB (const (==)) , testApplicativeLaws2 pEi pU pU pB (const (==)) , testApplicativeLaws2 pLs pU pU pB (const (==)) , testApplicativeLaws3 pMb pU pU pB pI (const (==)) , testApplicativeLaws3 pEi pU pU pB pI (const (==)) , testApplicativeLaws3 pLs pU pU pB pI (const (==)) ] , testGroup "Monad Laws" [ testMonadLaws1 pMb pU pU (const (==)) , testMonadLaws1 pEi pU pU (const (==)) , testMonadLaws1 pLs pU pU (const (==)) , testMonadLaws2 pMb pU pU pB (const (==)) , testMonadLaws2 pEi pU pU pB (const (==)) , testMonadLaws2 pLs pU pU pB (const (==)) , testMonadLaws3 pMb pU pU pB pI (const (==)) , testMonadLaws3 pEi pU pU pB pI (const (==)) , testMonadLaws3 pLs pU pU pB pI (const (==)) ] , testGroup "State Monad Laws" [ testStateMonadLaws pSU pU pU pU stateEq get put , testStateMonadLaws pSB pB pB pB stateEq get put , testStateMonadLaws pSI pI pI pI stateEq get put ] , testGroup "Reader Monad Laws" [ testReaderMonadLaws pRU pU pU pU pU readerEq ask local , testReaderMonadLaws pRB pB pB pB pB readerEq ask local , testReaderMonadLaws pRI pI pI pI pI readerEq ask local ] , testGroup "Error Monad Laws" [ testErrorMonadLaws pEU pU pU pU pU (const (==)) throw catch , testErrorMonadLaws pEB pU pB pU pU (const (==)) throw catch , testErrorMonadLaws pEI pU pI pU pU (const (==)) throw catch ] , testGroup "Writer Monads" [ testGroup "Writer Monad Laws" [ testWriterMonadLaws pWU pU pU pU pU (const (==)) tell draft , testWriterMonadLaws (pWLs pB) pU (pLs' pB) pU pU (const (==)) tell draft , testWriterMonadLaws (pWLs pI) pU (pLs' pI) pU pU (const (==)) tell draft ] , testGroup "Writer Monad Equivalences" [ testWriterMonadEquivalences pWU pU pU pU (const (==)) tell draft listen pass , testWriterMonadEquivalences (pWLs pB) pU (pLs' pB) pU (const (==)) tell draft listen pass , testWriterMonadEquivalences (pWLs pI) pU (pLs' pI) pU (const (==)) tell draft listen pass ] ] , testGroup "Maybe Monads" [ testMaybeMonadLaws pMb pU pU eqMaybe Nothing , testMaybeMonadLaws pMb pU pB eqMaybe Nothing , testMaybeMonadLaws pMb pU pI eqMaybe Nothing ] ] pU = Proxy :: Proxy () pB = Proxy :: Proxy Bool pI = Proxy :: Proxy Int pMb = Proxy :: Proxy Maybe pEi = Proxy :: Proxy (Either Int) pLs = Proxy :: Proxy [] pLs' = const Proxy :: Proxy a -> Proxy [a] pSU = Proxy :: Proxy (State ()) pSB = Proxy :: Proxy (State Bool) pSI = Proxy :: Proxy (State Int) pRU = Proxy :: Proxy (Reader ()) pRB = Proxy :: Proxy (Reader Bool) pRI = Proxy :: Proxy (Reader Int) pEU = Proxy :: Proxy (Error ()) pEB = Proxy :: Proxy (Error Bool) pEI = Proxy :: Proxy (Error Int) pWU = Proxy :: Proxy (Writer ()) pWLs = const Proxy :: Proxy a -> Proxy (Writer [a]) eqMaybe :: (Eq a) => () -> Maybe a -> Maybe a -> Bool eqMaybe () = (==) -- Basic State Monad data State s a = State { runState :: s -> (a,s) } stateEq :: (Eq s, Eq a) => s -> State s a -> State s a -> Bool stateEq s x y = (runState x s) == (runState y s) instance Monad (State s) where return a = State $ \s -> (a,s) x >>= f = State $ \s1 -> let (a,s2) = runState x s1 in runState (f a) s2 instance Applicative (State s) where pure = return (<*>) = ap instance Functor (State s) where fmap f x = x >>= (return . f) instance (Arbitrary a) => Arbitrary (State s a) where arbitrary = return <$> arbitrary get :: State s s get = State $ \s -> (s,s) put :: s -> State s () put s = State $ \_ -> ((),s) -- Basic Reader Monad data Reader r a = Reader { runReader :: r -> a } readerEq :: (Eq a) => r -> Reader r a -> Reader r a -> Bool readerEq r x y = (runReader x r) == (runReader y r) instance Monad (Reader r) where return a = Reader $ \_ -> a x >>= f = Reader $ \r -> let a = runReader x r in runReader (f a) r instance Applicative (Reader r) where pure = return (<*>) = ap instance Functor (Reader r) where fmap f x = x >>= (return . f) instance (Arbitrary a, CoArbitrary r) => Arbitrary (Reader r a) where arbitrary = Reader <$> arbitrary instance Show (Reader r a) where show _ = "" ask :: Reader r r ask = Reader $ \r -> r local :: (r -> r) -> Reader r a -> Reader r a local u x = Reader $ \r -> runReader x (u r) -- Basic Error Monad data Error e a = Error { runError :: Either e a } deriving (Eq, Show) instance Monad (Error e) where return a = Error (Right a) x >>= f = case x of Error (Left e) -> Error (Left e) Error (Right a) -> f a instance Applicative (Error e) where pure = return (<*>) = ap instance Functor (Error e) where fmap f x = x >>= (return . f) instance (Arbitrary a, Arbitrary e) => Arbitrary (Error e a) where arbitrary = Error <$> arbitrary throw :: e -> Error e a throw e = Error (Left e) catch :: Error e a -> (e -> Error e a) -> Error e a catch x h = case x of Error (Right a) -> Error (Right a) Error (Left e) -> h e -- Basic Writer Monad data Writer w a = Writer { runWriter :: (a,w) } deriving (Eq, Show) instance (Monoid w) => Monad (Writer w) where return a = Writer (a, mempty) x >>= f = let (a,w1) = runWriter x (b,w2) = runWriter (f a) in Writer (b, mappend w1 w2) instance (Monoid w) => Applicative (Writer w) where pure = return (<*>) = ap instance (Monoid w) => Functor (Writer w) where fmap f x = x >>= (return . f) instance (Arbitrary w, Arbitrary a) => Arbitrary (Writer w a) where arbitrary = Writer <$> arbitrary tell :: w -> Writer w () tell w = Writer ((),w) draft :: (Monoid w) => Writer w a -> Writer w (a,w) draft x = let (a,w) = runWriter x in Writer ((a,w), mempty) listen :: Writer w a -> Writer w (a,w) listen x = let (a,w) = runWriter x in Writer ((a,w), w) pass :: Writer w (a, w -> w) -> Writer w a pass x = let ((a,f),w) = runWriter x in Writer (a, f w)