exotic-list-monads 1.1.0 → 1.1.1
raw patch · 5 files changed
+111/−111 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Control.Monad.List.Exotic: instance forall k (m :: k -> *) (a :: k). GHC.Classes.Eq (m a) => GHC.Classes.Eq (Control.Monad.List.Exotic.DualListMonad m a)
+ Control.Monad.List.Exotic: instance forall k (m :: k -> *) (a :: k). GHC.Show.Show (m a) => GHC.Show.Show (Control.Monad.List.Exotic.DualListMonad m a)
- Control.Monad.List.Exotic: class (ListMonad m) => FreeRBPM m (c :: * -> Constraint) | m -> c
+ Control.Monad.List.Exotic: class (ListMonad m) => FreeRBPM m (c :: Type -> Constraint) | m -> c
- Control.Monad.List.NonEmpty.Exotic: class (NonEmptyMonad m) => FreeRBM m (c :: * -> Constraint) | m -> c
+ Control.Monad.List.NonEmpty.Exotic: class (NonEmptyMonad m) => FreeRBM m (c :: Type -> Constraint) | m -> c
Files
- CHANGELOG.md +8/−0
- exotic-list-monads.cabal +1/−1
- src/Control/Monad/List/Exotic.hs +43/−61
- src/Control/Monad/List/NonEmpty/Exotic.hs +27/−42
- test/Control/Monad/List/ExoticSpec.hs +32/−7
CHANGELOG.md view
@@ -1,5 +1,13 @@ # exotic-list-monad changelog +## v1.1.1++- Refactor to avoid the noncanonical-monad-instances and star-is-type warnings++- Add Eq and Show instances to DualListMonad++- Fixes in documentation+ ## v1.1.0 - Add the AtMost monad
exotic-list-monads.cabal view
@@ -7,7 +7,7 @@ -- hash: 5b5385de8f22ca1f51a19de7b8b393b9012fded676d9ea7412ac96fde7fc9d83 name: exotic-list-monads-version: 1.1.0+version: 1.1.1 synopsis: Non-standard monads on lists and non-empty lists description: The usual list monad is only one of infinitely many ways to turn the list functor into a monad. The same applies to the usual non-empty list monad and the non-empty list functor. This library collects such non-standard "list" and "non-empty list" monads. category: List, Monads
src/Control/Monad/List/Exotic.hs view
@@ -174,6 +174,7 @@ import Prelude hiding ((<>)) import Control.Monad (ap, join)+import Data.Kind (Type) import GHC.Exts (IsList(..), IsString(..), Constraint) import GHC.TypeLits import Data.Proxy@@ -212,25 +213,20 @@ -- | Every list monad has a dual, in which join is defined as -- -- @--- join . reverse . fmap reverse+-- reverse . join . reverse . fmap reverse -- @ ----- (where join is the join of the original list monad), while return is------ @--- reverse . return--- @+-- (where join is the join of the original list monad). ----- (where return is the return of the original list monad).+-- return is the same as in the original monad. newtype DualListMonad m a = DualListMonad { unDualListMonad :: m a }- deriving (Functor)+ deriving (Functor, Show, Eq) instance (ListMonad m) => Applicative (DualListMonad m) where- pure = return+ pure = DualListMonad . pure (<*>) = ap instance (ListMonad m) => Monad (DualListMonad m) where- return = DualListMonad . liftListFun reverse . return DualListMonad m >>= f = DualListMonad $ liftListFun reverse $ liftListFun reverse m >>= liftListFun reverse . unDualListMonad . f @@ -278,7 +274,7 @@ -- | A class for __free right-braketed__ (subclasses of) -- __pointed magmas__. ----- Most of the monads defined in this module arise from subclasses of+-- All monads defined in this section arise from subclasses of -- 'PointedMagma', in which we do not assume any additional methods, -- but require the instances to satisfy additional equations. This -- means that the monad is not only an instance of such a class that@@ -321,7 +317,7 @@ -- @ -- instance FreeRBPM [] 'Data.Monoid.Monoid' -- @-class (ListMonad m) => FreeRBPM m (c :: * -> Constraint) | m -> c where+class (ListMonad m) => FreeRBPM m (c :: Type -> Constraint) | m -> c where foldRBPM :: (PointedMagma a, c a) => (x -> a) -> m x -> a foldRBPM _ (unwrap -> []) = eps foldRBPM f (unwrap -> xs) = foldr1 (<>) (map f xs)@@ -345,8 +341,8 @@ -- | The Global Failure monad arises from free zero semigroups. It -- implements a kind of nondeterminism similar to the usual List--- monad, but failing (= producing an empty list) in one branch makes--- the entire computation fail. Its join is defined as:+-- monad, but failing (= resulting in the empty list) in one branch+-- makes the entire computation fail. Its join is defined as: -- -- @ -- join xss | any null xss = []@@ -365,11 +361,10 @@ deriving instance IsString (GlobalFailure Char) instance Applicative GlobalFailure where- pure = return- (<*>) = ap+ pure x = GlobalFailure [x]+ (<*>) = ap instance Monad GlobalFailure where- return x = GlobalFailure [x] GlobalFailure xs >>= f = GlobalFailure $ join $ map (unGlobalFailure . f) xs where join xss | any null xss = []@@ -460,11 +455,10 @@ deriving instance IsString (MazeWalk Char) instance Applicative MazeWalk where- pure = return- (<*>) = ap+ pure x = MazeWalk [x]+ (<*>) = ap instance Monad MazeWalk where- return x = MazeWalk [x] MazeWalk xs >>= f = MazeWalk $ join $ map (unMazeWalk . f) xs where join xss | null xss || any null xss@@ -532,11 +526,10 @@ deriving instance IsString (DiscreteHybrid Char) instance Applicative DiscreteHybrid where- pure = return- (<*>) = ap+ pure x = DiscreteHybrid [x]+ (<*>) = ap instance Monad DiscreteHybrid where- return x = DiscreteHybrid [x] DiscreteHybrid xs >>= f = DiscreteHybrid $ join $ map (unDiscreteHybrid . f) xs where join xss | null xss = []@@ -601,11 +594,10 @@ deriving instance IsString (ListUnfold Char) instance Applicative ListUnfold where- pure = return- (<*>) = ap+ pure x = ListUnfold [x]+ (<*>) = ap instance Monad ListUnfold where- return x = ListUnfold [x] ListUnfold xs >>= f = ListUnfold $ join $ map (unListUnfold . f) xs where join xss | null xss || any null xss@@ -674,7 +666,7 @@ -- -- The 'Stutter' monad is quite similar to 'ListUnfold'. The -- difference is that when the latter fails (that is, its join results--- in an empty list), the former stutters on the last singleton.+-- in the empty list), the former stutters on the last singleton. -- -- Examples: --@@ -690,11 +682,10 @@ deriving instance (KnownNat n) => IsString (Stutter n Char) instance (KnownNat n) => Applicative (Stutter n) where- pure = return- (<*>) = ap+ pure x = Stutter [x]+ (<*>) = ap instance (KnownNat n) => Monad (Stutter n) where- return x = Stutter [x] Stutter xs >>= f = Stutter $ join $ map (unStutter . f) xs where join xss | null xss@@ -736,7 +727,7 @@ -- | The stutter-keeper monad arises from free stutter-keeper -- algebras. Its join stutters (as in the 'Stutter' monad) if the--- first non-singleton list in empty. Otherwise, it keeps the+-- first non-singleton list is empty. Otherwise, it keeps the -- singleton prefix, and keeps the first non-singleton list. The join -- can thus be defined as follows (omitting the conversion of the -- type-level 'Nat' @n@ to a run-time value):@@ -765,11 +756,10 @@ deriving instance (KnownNat n) => IsString (StutterKeeper n Char) instance (KnownNat n) => Applicative (StutterKeeper n) where- pure = return- (<*>) = ap+ pure x = StutterKeeper [x]+ (<*>) = ap instance (KnownNat n) => Monad (StutterKeeper n) where- return x = StutterKeeper [x] StutterKeeper xs >>= f = StutterKeeper $ join $ map (unStutterKeeper . f) xs where join xss | null xss@@ -844,11 +834,10 @@ deriving instance (KnownNat n, KnownNat m) => IsString (StutterStutter n m Char) instance (KnownNat n, KnownNat m) => Applicative (StutterStutter n m) where- pure = return- (<*>) = ap+ pure x = StutterStutter [x]+ (<*>) = ap instance (KnownNat n, KnownNat m) => Monad (StutterStutter n m) where- return x = StutterStutter [x] StutterStutter xs >>= f = StutterStutter $ join $ map (unStutterStutter . f) xs where join xss | null xss@@ -922,14 +911,14 @@ -- -- Below, we first show a couple of concrete examples of monads -- arising from particular numerical monoids, and then the general--- version via a set of generators.+-- version via a set of generators, @'NumericalMonoidMonad'@. -------------------- -- The Mini monad -- -------------------- -- | The Mini monad is, in a sense, a minimal list monad, meaning that--- its join fails (= results in an empty list) for all values except+-- its join fails (= results in the empty list) for all values except -- the ones that appear in the unit laws (i.e., a singleton or a list -- of singletons): --@@ -958,11 +947,10 @@ deriving instance IsString (Mini Char) instance Applicative Mini where- pure = return- (<*>) = ap+ pure x = Mini [x]+ (<*>) = ap instance Monad Mini where- return x = Mini [x] Mini xs >>= f = Mini $ join $ map (unMini . f) xs where join xss | isSingle xss || all isSingle xss = concat xss@@ -982,7 +970,7 @@ -- | The join of the Odd monad is a concat of the inner lists provided -- there is an odd number of them, and that all of them are of odd -- length themselves. Otherwise (modulo cases needed for the unit--- laws), it returns an empty list.+-- laws), the result is the empty list. -- -- @ -- join xss | isSingle xss || all isSingle xss = concat xss@@ -1011,11 +999,10 @@ deriving instance IsString (Odd Char) instance Applicative Odd where- pure = return- (<*>) = ap+ pure x = Odd [x]+ (<*>) = ap instance Monad Odd where- return x = Odd [x] Odd xs >>= f = Odd $ join $ map (unOdd . f) xs where join xss | isSingle xss || all isSingle xss@@ -1071,11 +1058,10 @@ deriving instance (KnownNat n) => IsString (AtLeast n Char) instance (KnownNat n) => Applicative (AtLeast n) where- pure = return- (<*>) = ap+ pure x = AtLeast [x]+ (<*>) = ap instance (KnownNat n) => Monad (AtLeast n) where- return x = AtLeast [x] AtLeast xs >>= f = AtLeast $ join $ map (unAtLeast . f) xs where join xss | isSingle xss = concat xss@@ -1148,11 +1134,10 @@ deriving instance IsString (NumericalMonoidMonad ns Char) instance (NumericalMonoidGenerators ns) => Applicative (NumericalMonoidMonad ns) where- pure = return- (<*>) = ap+ pure x = NumericalMonoidMonad [x]+ (<*>) = ap instance (NumericalMonoidGenerators ns) => Monad (NumericalMonoidMonad ns) where- return x = NumericalMonoidMonad [x] NumericalMonoidMonad xs >>= f = NumericalMonoidMonad $ join $ map (unNumericalMonoidMonad . f) xs where join xss | isSingle xss || all isSingle xss = concat xss@@ -1204,11 +1189,10 @@ deriving instance (KnownNat n) => IsString (AtMost n Char) instance (KnownNat n) => Applicative (AtMost n) where- pure = return- (<*>) = ap+ pure x = AtMost [x]+ (<*>) = ap instance (KnownNat n) => Monad (AtMost n) where- return x = AtMost [x] AtMost xs >>= f = AtMost $ join $ map (unAtMost . f) xs where join xss | isSingle xss || all isSingle xss = concat xss@@ -1298,11 +1282,10 @@ deriving instance IsString (ContinuumOfMonads s Char) instance (SetOfNats s) => Applicative (ContinuumOfMonads s) where- pure = return- (<*>) = ap+ pure x = ContinuumOfMonads [x]+ (<*>) = ap instance (SetOfNats s) => Monad (ContinuumOfMonads s) where- return x = ContinuumOfMonads [x] ContinuumOfMonads xs >>= f = ContinuumOfMonads $ join $ map (unContinuumOfMonads . f) xs where join xss | isSingle xss || all isSingle xss = concat xss@@ -1352,11 +1335,10 @@ deriving instance (KnownNat n, KnownNat p) => IsString (ShortStutterKeeper n p Char) instance (KnownNat n, KnownNat p) => Applicative (ShortStutterKeeper n p) where- pure = return- (<*>) = ap+ pure x = ShortStutterKeeper [x]+ (<*>) = ap instance (KnownNat n, KnownNat p) => Monad (ShortStutterKeeper n p) where- return x = ShortStutterKeeper [x] ShortStutterKeeper xs >>= f = ShortStutterKeeper $ join $ map (unShortStutterKeeper . f) xs where join :: forall x. [[x]] -> [x]
src/Control/Monad/List/NonEmpty/Exotic.hs view
@@ -170,6 +170,7 @@ import qualified Data.List.NonEmpty as NonEmpty import Prelude hiding ((<>)) import Control.Monad (ap, join)+import Data.Kind (Type) import GHC.Exts (IsList(..), IsString(..), Constraint) import GHC.TypeLits import Data.Proxy@@ -284,7 +285,7 @@ -- @ -- instance FreeRBM 'NonEmpty' 'Data.Semigroup.Semigroup' -- @-class (NonEmptyMonad m) => FreeRBM m (c :: * -> Constraint) | m -> c where+class (NonEmptyMonad m) => FreeRBM m (c :: Type -> Constraint) | m -> c where foldRBM :: (Magma a, c a) => (x -> a) -> m x -> a foldRBM f (unwrap -> toList -> xs) = foldr1 (<>) (map f xs) @@ -319,11 +320,10 @@ deriving (Functor, Show, Eq) instance Applicative Keeper where- pure = return- (<*>) = ap+ pure a = Keeper $ [a] -- OverloadedLists+ (<*>) = ap instance Monad Keeper where- return a = Keeper $ [a] -- OverloadedLists Keeper xs >>= f = Keeper $ join $ NonEmpty.map (unKeeper . f) xs where@@ -380,11 +380,10 @@ deriving (Functor, Show, Eq) instance Applicative DiscreteHybridNE where- pure = return- (<*>) = ap+ pure a = DiscreteHybridNE $ [a] -- OverloadedLists+ (<*>) = ap instance Monad DiscreteHybridNE where- return a = DiscreteHybridNE $ [a] -- OverloadedLists DiscreteHybridNE xs >>= f = DiscreteHybridNE $ join $ NonEmpty.map (unDiscreteHybridNE . f) xs where@@ -439,11 +438,10 @@ deriving (Functor, Show, Eq) instance Applicative OpDiscreteHybridNE where- pure = return- (<*>) = ap+ pure a = OpDiscreteHybridNE $ [a] -- OverloadedLists+ (<*>) = ap instance Monad OpDiscreteHybridNE where- return a = OpDiscreteHybridNE $ [a] -- OverloadedLists OpDiscreteHybridNE xs >>= f = OpDiscreteHybridNE $ join $ NonEmpty.map (unOpDiscreteHybridNE . f) xs where@@ -499,11 +497,10 @@ deriving (Functor, Show, Eq) instance Applicative MazeWalkNE where- pure = return- (<*>) = ap+ pure a = MazeWalkNE $ [a] -- OverloadedLists+ (<*>) = ap instance Monad MazeWalkNE where- return a = MazeWalkNE $ [a] -- OverloadedLists MazeWalkNE xs >>= f = MazeWalkNE $ join $ NonEmpty.map (unMazeWalkNE . f) xs where@@ -559,11 +556,10 @@ deriving (Functor, Show, Eq) instance (KnownNat n) => Applicative (StutterNE n) where- pure = return- (<*>) = ap+ pure a = StutterNE $ [a] -- OverloadedLists+ (<*>) = ap instance (KnownNat n) => Monad (StutterNE n) where- return a = StutterNE $ [a] -- OverloadedLists StutterNE xs >>= f = StutterNE $ join $ NonEmpty.map (unStutterNE . f) xs where@@ -665,11 +661,10 @@ deriving (Functor, Show, Eq) instance Applicative HeadTails where- pure = return- (<*>) = ap+ pure a = HeadTails $ [a,a] -- OverloadedLists+ (<*>) = ap instance Monad HeadTails where- return a = HeadTails $ [a,a] -- OverloadedLists HeadTails xs >>= f = HeadTails $ join $ NonEmpty.map (unHeadTails . f) xs where join ((x :| _) :| xss) = x :| concatMap NonEmpty.tail xss@@ -770,11 +765,10 @@ deriving (Functor, Show, Eq) instance Applicative HeadsTail where- pure = return- (<*>) = ap+ pure a = HeadsTail $ [a,a] -- OverloadedLists+ (<*>) = ap instance Monad HeadsTail where- return a = HeadsTail $ [a,a] -- OverloadedLists HeadsTail xs >>= f = HeadsTail $ join $ NonEmpty.map (unHeadsTail . f) xs where join xss@(splitSnoc -> (xss', xs@(_:|ys)))@@ -840,11 +834,10 @@ deriving (Functor, Show, Eq) instance Applicative AlphaOmega where- pure = return- (<*>) = ap+ pure a = AlphaOmega [a] -- OverloadedLists+ (<*>) = ap instance Monad AlphaOmega where- return a = AlphaOmega [a] -- OverloadedLists AlphaOmega xs >>= f = AlphaOmega $ join $ NonEmpty.map (unAlphaOmega . f) xs where join xss | isSingle xss || nonEmptyAll isSingle xss@@ -882,26 +875,21 @@ -- as -- -- @--- join . reverse . fmap reverse+-- reverse . join . reverse . fmap reverse -- @ ----- (where join is the join of the original list monad), while return is------ @--- reverse . return--- @+-- (where join is the join of the original list monad). ----- (where return is the return of the original list monad).+-- return is the same as in the original monad. newtype DualNonEmptyMonad m a = DualNonEmptyMonad { unDualNonEmptyMonad :: m a } deriving (Functor, Show, Eq) instance (NonEmptyMonad m) => Applicative (DualNonEmptyMonad m) where- pure = return- (<*>) = ap+ pure = DualNonEmptyMonad . liftNEFun NonEmpty.reverse . pure+ (<*>) = ap instance (NonEmptyMonad m) => Monad (DualNonEmptyMonad m) where- return = DualNonEmptyMonad . liftNEFun NonEmpty.reverse . return DualNonEmptyMonad m >>= f = DualNonEmptyMonad $ liftNEFun NonEmpty.reverse $ liftNEFun NonEmpty.reverse m >>= liftNEFun NonEmpty.reverse . unDualNonEmptyMonad . f@@ -934,11 +922,10 @@ deriving (Functor, Show, Eq) instance (ListMonad m) => Applicative (IdXList m) where- pure = return- (<*>) = ap+ pure x = IdXList x (pure x)+ (<*>) = ap instance (ListMonad m) => Monad (IdXList m) where- return x = IdXList x (return x) IdXList x m >>= f = IdXList (componentId $ f x) (m >>= componentM . f) instance (ListMonad m) => IsNonEmpty (IdXList m a) where@@ -1010,11 +997,10 @@ deriving (Functor, Show, Eq) instance (HasShortFront m, KnownNat p) => Applicative (ShortFront m p) where- pure = return+ pure = ShortFront . return (<*>) = ap instance (HasShortFront m, KnownNat p) => Monad (ShortFront m p) where- return = ShortFront . return ShortFront m >>= f | isSingle (unwrap m) || nonEmptyAll isSingle (unwrap $ unwrap . unShortFront . f <$> m)@@ -1075,14 +1061,13 @@ deriving (Functor, Show, Eq) instance (HasShortRear m, KnownNat p) => Applicative (ShortRear m p) where- pure = return+ pure = ShortRear . pure (<*>) = ap nonEmptyTakeRear :: Int -> NonEmpty a -> [a] nonEmptyTakeRear p = reverse . NonEmpty.take p . NonEmpty.reverse instance (HasShortRear m, KnownNat p) => Monad (ShortRear m p) where- return = ShortRear . return ShortRear m >>= f | isSingle (unwrap m) || nonEmptyAll isSingle (unwrap $ unwrap . unShortRear . f <$> m)
test/Control/Monad/List/ExoticSpec.hs view
@@ -23,6 +23,7 @@ import Data.Proxy import GHC.Exts (IsList(..)) +deriving instance (Arbitrary (m a)) => Arbitrary (DualListMonad m a) deriving instance (Arbitrary a) => Arbitrary (GlobalFailure a) deriving instance (Arbitrary a) => Arbitrary (MazeWalk a) deriving instance (Arbitrary a) => Arbitrary (DiscreteHybrid a)@@ -98,7 +99,8 @@ it "knows that last of non-empty is non-empty" $ safeLast "Roy" `shouldBe` "y" - testMonad "GlobalFailure" (Proxy :: Proxy GlobalFailure)+ testMonad "GlobalFailure" (Proxy :: Proxy GlobalFailure)+ testMonad "DualListMonad GlobalFailure" (Proxy :: Proxy (DualListMonad GlobalFailure)) describe "GlobalFailure is ZeroSemigroup" $ do it "x <> eps == eps" $ property $ \(x :: GlobalFailure Int) -> x <> eps == eps@@ -106,7 +108,9 @@ $ property $ \(x :: GlobalFailure Int) -> eps <> x == eps it "(x <> y) <> z == x <> (y <> z)" $ property $ \(x :: GlobalFailure Int) y z -> (x <> y) <> z == x <> (y <> z)- testMonad "MazeWalk" (Proxy :: Proxy MazeWalk)+ + testMonad "MazeWalk" (Proxy :: Proxy MazeWalk)+ testMonad "DualListMonad MazeWalk" (Proxy :: Proxy (DualListMonad MazeWalk)) describe "MazeWalk is PalindromeAlgebra" $ do it "x <> eps == eps" $ property $ \(x :: MazeWalk Int) -> x <> eps == eps@@ -114,7 +118,9 @@ $ property $ \(x :: MazeWalk Int) -> eps <> x == eps it "(x <> y) <> z == x <> (y <> (x <> z))" $ property $ \(x :: MazeWalk Int) y z -> (x <> y) <> z == x <> (y <> (x <> z))- testMonad "DiscreteHybrid" (Proxy :: Proxy DiscreteHybrid)+ + testMonad "DiscreteHybrid" (Proxy :: Proxy DiscreteHybrid)+ testMonad "DualListMonad DiscreteHybrid" (Proxy :: Proxy (DualListMonad DiscreteHybrid)) describe "DiscreteHybrid is LeaningAlgebra" $ do it "x <> eps == eps" $ property $ \(x :: DiscreteHybrid Int) -> x <> eps == eps@@ -122,7 +128,9 @@ $ property $ \(x :: DiscreteHybrid Int) -> eps <> x == x it "(x <> y) <> z == y <> z" $ property $ \(x :: DiscreteHybrid Int) y z -> (x <> y) <> z == y <> z- testMonad "ListUnfold" (Proxy :: Proxy ListUnfold)+ + testMonad "ListUnfold" (Proxy :: Proxy ListUnfold)+ testMonad "DualListMonad ListUnfold" (Proxy :: Proxy (DualListMonad ListUnfold)) describe "ListUnfold is SkewedAlgebra" $ do it "x <> eps == eps" $ property $ \(x :: ListUnfold Int) -> x <> eps == eps@@ -131,10 +139,15 @@ it "(x <> y) <> z == eps" $ property $ \(x :: ListUnfold Int) y z -> (x <> y) <> z == eps - testMonad "Stutter 1" (Proxy :: Proxy (Stutter 0))- testMonad "Stutter 2" (Proxy :: Proxy (Stutter 1))+ testMonad "Stutter 1" (Proxy :: Proxy (Stutter 1))+ testMonad "Stutter 2" (Proxy :: Proxy (Stutter 2)) testMonad "Stutter 5" (Proxy :: Proxy (Stutter 5)) + testMonad "DualListMonad (Stutter 0)" (Proxy :: Proxy (DualListMonad (Stutter 0)))+ testMonad "DualListMonad (Stutter 1)" (Proxy :: Proxy (DualListMonad (Stutter 1)))+ testMonad "DualListMonad (Stutter 2)" (Proxy :: Proxy (DualListMonad (Stutter 2)))+ testMonad "DualListMonad (Stutter 5)" (Proxy :: Proxy (DualListMonad (Stutter 5)))+ testMonad "StutterKeeper 0" (Proxy :: Proxy (StutterKeeper 0)) testMonad "StutterKeeper 1" (Proxy :: Proxy (StutterKeeper 1)) testMonad "StutterKeeper 2" (Proxy :: Proxy (StutterKeeper 2))@@ -142,6 +155,11 @@ testMonad "StutterKeeper 4" (Proxy :: Proxy (StutterKeeper 4)) testMonad "StutterKeeper 5" (Proxy :: Proxy (StutterKeeper 5)) testMonad "StutterKeeper 10" (Proxy :: Proxy (StutterKeeper 10))++ testMonad "DualListMonad (StutterKeeper 0)" (Proxy :: Proxy (DualListMonad (StutterKeeper 0)))+ testMonad "DualListMonad (StutterKeeper 1)" (Proxy :: Proxy (DualListMonad (StutterKeeper 1)))+ testMonad "DualListMonad (StutterKeeper 2)" (Proxy :: Proxy (DualListMonad (StutterKeeper 2)))+ testMonad "DualListMonad (StutterKeeper 5)" (Proxy :: Proxy (DualListMonad (StutterKeeper 5))) testMonad "StutterStutter 0 0" (Proxy :: Proxy (StutterStutter 0 0)) testMonad "StutterStutter 0 1" (Proxy :: Proxy (StutterStutter 0 1))@@ -192,9 +210,16 @@ testMonad "ShortStutterKeeper 0 0" (Proxy :: Proxy (ShortStutterKeeper 0 0)) testMonad "ShortStutterKeeper 0 1" (Proxy :: Proxy (ShortStutterKeeper 0 1))- testMonad "ShortStutterKeeper 0 1" (Proxy :: Proxy (ShortStutterKeeper 1 0))+ testMonad "ShortStutterKeeper 1 0" (Proxy :: Proxy (ShortStutterKeeper 1 0)) testMonad "ShortStutterKeeper 1 1" (Proxy :: Proxy (ShortStutterKeeper 1 1)) testMonad "ShortStutterKeeper 5 3" (Proxy :: Proxy (ShortStutterKeeper 5 3)) testMonad "ShortStutterKeeper 3 5" (Proxy :: Proxy (ShortStutterKeeper 3 5))++ testMonad "DualListMonad (ShortStutterKeeper 0 0)" (Proxy :: Proxy (DualListMonad (ShortStutterKeeper 0 0)))+ testMonad "DualListMonad (ShortStutterKeeper 0 1)" (Proxy :: Proxy (DualListMonad (ShortStutterKeeper 0 1)))+ testMonad "DualListMonad (ShortStutterKeeper 1 0)" (Proxy :: Proxy (DualListMonad (ShortStutterKeeper 1 0)))+ testMonad "DualListMonad (ShortStutterKeeper 1 1)" (Proxy :: Proxy (DualListMonad (ShortStutterKeeper 1 1)))+ testMonad "DualListMonad (ShortStutterKeeper 5 3)" (Proxy :: Proxy (DualListMonad (ShortStutterKeeper 5 3)))+ testMonad "DualListMonad (ShortStutterKeeper 3 5)" (Proxy :: Proxy (DualListMonad (ShortStutterKeeper 3 5)))