{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
module Main (main) where
import Control.Comonad
import Control.Comonad.Coaction
import Control.Comonad.Store
import Control.Comonad.Traced (TracedT (..))
import Data.Functor.Compose
import Data.List.NonEmpty qualified as NE
import Data.Monoid (Sum)
import Data.Tree
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.Tasty
import Test.Tasty.QuickCheck
leftcomodule ::
forall w f a.
( LeftComodule w f,
Arbitrary (f a),
Show (f a),
EqProp (f a),
EqProp (w (w (f a)))
) =>
TestBatch
leftcomodule =
( "left comodule laws",
[ ("left coidentity", property leftP),
("coassociativity", property coassocP)
]
)
where
leftP :: f a -> Property
coassocP :: f a -> Property
leftP a = extract (lduplicate @w a) =-= a
coassocP a = duplicate @w (lduplicate a) =-= fmap lduplicate (lduplicate a)
leftcomodulestore ::
forall w s a.
( Comonad w,
Arbitrary s,
Arbitrary (w (Fun s a)),
Show s,
EqProp s,
EqProp (w a),
Show (w (Fun s a)),
EqProp (w (w (w a, s))),
ComonadTransStack w (StoreT s w)
) =>
TestBatch
leftcomodulestore =
( "left comodule laws for StoreT",
[ ("right coidentity", property leftP),
("associativity", property coassocP)
]
)
where
leftP :: w (Fun s a) -> s -> s -> Property
coassocP :: w (Fun s a) -> s -> s -> Property
leftP a s t =
let x@(StoreT f1 s1) = StoreT (applyFun <$> a) s
StoreT f2 s2 = extract (lduplicate @w x)
in (($ t) <$> f1, s1) =-= (($ t) <$> f2, s2)
coassocP a s t =
let x = StoreT (applyFun <$> a) s
w1 = fmap (\(StoreT f u) -> (($ t) <$> f, u)) <$> duplicate @w (lduplicate x)
w2 = fmap (\(StoreT f u) -> (($ t) <$> f, u)) <$> fmap lduplicate (lduplicate x)
in w1 =-= w2
leftcomoduletraced ::
forall w m a.
( Comonad w,
Arbitrary m,
Arbitrary a,
Monoid m,
EqProp (w a),
Arbitrary (w (Fun m a)),
Show m,
Show (w (Fun m a)),
EqProp (w (w (w a))),
ComonadTransStack w (TracedT m w)
) =>
TestBatch
leftcomoduletraced =
( "left comodule laws for TracedT",
[ ("right coidentity", property leftP),
("associativity", property coassocP)
]
)
where
leftP :: w (Fun m a) -> m -> Property
coassocP :: w (Fun m a) -> m -> Property
leftP a t =
let x@(TracedT f1) = TracedT (applyFun <$> a)
TracedT f2 = extract (lduplicate @w x)
in (($ t) <$> f1) =-= (($ t) <$> f2)
coassocP a t =
let x = TracedT (applyFun <$> a)
w1 = fmap (\(TracedT f) -> ($ t) <$> f) <$> duplicate @w (lduplicate x)
w2 = fmap (\(TracedT f) -> ($ t) <$> f) <$> fmap lduplicate (lduplicate x)
in w1 =-= w2
rightcomodule ::
forall w f a.
( RightComodule w f,
EqProp (f a),
EqProp (f (w (w a))),
Arbitrary (f a),
Show (f a)
) =>
TestBatch
rightcomodule =
( "right comodule laws",
[ ("right coidentity", property rightP),
("coassociativity", property coassocP)
]
)
where
rightP :: f a -> Property
coassocP :: f a -> Property
rightP a = fmap extract (rduplicate @w a) =-= a
coassocP a = fmap duplicate (rduplicate @w a) =-= fmap rduplicate (rduplicate a)
rightcomodulestore ::
forall w s a.
( Comonad w,
Arbitrary s,
Arbitrary (w (Fun s a)),
Show s,
Show (w (Fun s a)),
EqProp s,
EqProp (w a),
EqProp (w (w (w a))),
ComonadTransStack w (StoreT s w)
) =>
TestBatch
rightcomodulestore =
( "right comodule laws for StoreT",
[ ("right coidentity", property rightP),
("associativity", property coassocP)
]
)
where
rightP :: w (Fun s a) -> s -> s -> Property
coassocP :: w (Fun s a) -> s -> s -> Property
rightP a s t =
let x@(StoreT f1 s1) = StoreT (applyFun <$> a) s
StoreT f2 s2 = fmap extract (rduplicate @w x)
in (($ t) <$> f1, s1) =-= (($ t) <$> f2, s2)
coassocP a s t =
let x = StoreT (applyFun <$> a) s
StoreT f1 s1 = fmap duplicate (rduplicate @w x)
StoreT f2 s2 = fmap rduplicate (rduplicate x)
in (($ t) <$> f1, s1) =-= (($ t) <$> f2, s2)
bicomodule ::
forall s t f a.
( BiComodule s t f,
Arbitrary a,
EqProp (s (f (t a))),
Arbitrary (f a),
Show (f a)
) =>
TestBatch
bicomodule =
( "bicomodule laws",
[ ("coassociativity 1", property assoc1P),
("coassociativity 2", property assoc2P)
]
)
where
assoc1P :: f a -> Property
assoc2P :: f a -> Property
assoc1P a = biduplicate @s @t a =-= lduplicate (rduplicate a)
assoc2P a = biduplicate @s @t a =-= fmap rduplicate (lduplicate a)
instance (EqProp a) => EqProp (Tree a)
main :: IO ()
main =
defaultMain
( testGroup "monad action laws"
$ uncurry testProperties
<$> [ leftcomodule @NE.NonEmpty @(Compose NE.NonEmpty Maybe) @Int,
rightcomodule @NE.NonEmpty @(Compose Maybe NE.NonEmpty) @Int,
rightcomodulestore @NE.NonEmpty @Bool @Int,
rightcomodulestore @Tree @Char @Int,
leftcomodulestore @Tree @Char @Char,
leftcomoduletraced @Tree @(Sum Int) @Char
]
)