polysemy-check 0.4.0.0 → 0.5.0.0
raw patch · 9 files changed
+333/−296 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Polysemy.Check.Arbitrary.AnyEff: [SomeAction] :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a)) => e (Sem r) a -> SomeAction e r
- Polysemy.Check.Arbitrary.AnyEff: [SomeEffOfType] :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a)) => e (Sem r) a -> SomeEffOfType r a
- Polysemy.Check.Arbitrary.AnyEff: [SomeEff] :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a)) => e (Sem r) a -> SomeEff r
- Polysemy.Check.Arbitrary.AnyEff: class ArbitraryAction (as :: [Type]) (e :: Effect) (r :: EffectRow)
- Polysemy.Check.Arbitrary.AnyEff: class ArbitraryEff (es :: EffectRow) (r :: EffectRow)
- Polysemy.Check.Arbitrary.AnyEff: class ArbitraryEffOfType (a :: Type) (es :: EffectRow) (r :: EffectRow)
- Polysemy.Check.Arbitrary.AnyEff: data SomeAction e (r :: EffectRow)
- Polysemy.Check.Arbitrary.AnyEff: data SomeEff (r :: EffectRow)
- Polysemy.Check.Arbitrary.AnyEff: data SomeEffOfType (r :: EffectRow) a
- Polysemy.Check.Arbitrary.AnyEff: genSomeAction :: ArbitraryAction as e r => [Gen (SomeAction e r)]
- Polysemy.Check.Arbitrary.AnyEff: genSomeEff :: ArbitraryEff es r => [Gen (SomeEff r)]
- Polysemy.Check.Arbitrary.AnyEff: genSomeEffOfType :: ArbitraryEffOfType a es r => [Gen (SomeEffOfType r a)]
- Polysemy.Check.Arbitrary.AnyEff: instance (GHC.Classes.Eq a, GHC.Show.Show a, GHC.Show.Show (e (Polysemy.Internal.Sem r) a), Polysemy.Check.Arbitrary.AnyEff.ArbitraryEffOfType a es r, Generics.Kind.GenericK e, Polysemy.Check.Arbitrary.Generic.GArbitraryK e (Generics.Kind.RepK e) r a, Test.QuickCheck.Arbitrary.CoArbitrary a, Polysemy.Internal.Union.Member e r) => Polysemy.Check.Arbitrary.AnyEff.ArbitraryEffOfType a (e : es) r
- Polysemy.Check.Arbitrary.AnyEff: instance (Polysemy.Check.Arbitrary.AnyEff.ArbitraryAction as e r, GHC.Classes.Eq a, GHC.Show.Show a, Polysemy.Internal.Union.Member e r, GHC.Show.Show (e (Polysemy.Internal.Sem r) a), Generics.Kind.GenericK e, Test.QuickCheck.Arbitrary.CoArbitrary a, Polysemy.Check.Arbitrary.Generic.GArbitraryK e (Generics.Kind.RepK e) r a) => Polysemy.Check.Arbitrary.AnyEff.ArbitraryAction (a : as) e r
- Polysemy.Check.Arbitrary.AnyEff: instance (Polysemy.Check.Arbitrary.AnyEff.ArbitraryEff es r, Polysemy.Check.Arbitrary.AnyEff.ArbitraryAction (Polysemy.Check.Arbitrary.AnyEff.TypesOf e) e r) => Polysemy.Check.Arbitrary.AnyEff.ArbitraryEff (e : es) r
- Polysemy.Check.Arbitrary.AnyEff: instance GHC.Show.Show (Polysemy.Check.Arbitrary.AnyEff.SomeAction e r)
- Polysemy.Check.Arbitrary.AnyEff: instance GHC.Show.Show (Polysemy.Check.Arbitrary.AnyEff.SomeEff r)
- Polysemy.Check.Arbitrary.AnyEff: instance Polysemy.Check.Arbitrary.AnyEff.ArbitraryAction '[] e r
- Polysemy.Check.Arbitrary.AnyEff: instance Polysemy.Check.Arbitrary.AnyEff.ArbitraryEff '[] r
- Polysemy.Check.Arbitrary.AnyEff: instance Polysemy.Check.Arbitrary.AnyEff.ArbitraryEffOfType a '[] r
- Polysemy.Check.Arbitrary.AnyEff: type TypesOf (e :: Effect) = GTypesOf (RepK e)
- Polysemy.Check.Arbitrary.AnyEff: type family ArbitraryForAll (e :: Effect) (as :: [Type]) (r :: EffectRow) :: Constraint
- Polysemy.Check.Arbitrary.Generic: class GArbitraryK (e :: Effect) (f :: LoT Effect -> Type) (r :: EffectRow) (a :: Type)
- Polysemy.Check.Arbitrary.Generic: class GArbitraryKTerm (t :: Type)
- Polysemy.Check.Arbitrary.Generic: data family ExistentialFor (e :: Effect)
- Polysemy.Check.Arbitrary.Generic: garbitraryk :: GArbitraryK e f r a => [Gen (f (LoT2 (Sem r) a))]
- Polysemy.Check.Arbitrary.Generic: garbitrarykterm :: GArbitraryKTerm t => Gen t
- Polysemy.Check.Arbitrary.Generic: genEff :: forall e r a. (GenericK e, GArbitraryK e (RepK e) r a) => Gen (e (Sem r) a)
- Polysemy.Check.Arbitrary.Generic: instance (Data.PolyKinded.Atom.Interpret c (Data.PolyKinded.LoT2 (Polysemy.Internal.Sem r) a), Polysemy.Check.Arbitrary.Generic.GArbitraryK e f r a) => Polysemy.Check.Arbitrary.Generic.GArbitraryK e (c Generics.Kind.:=>: f) r a
- Polysemy.Check.Arbitrary.Generic: instance (Polysemy.Check.Arbitrary.Generic.GArbitraryK e (Generics.Kind.Unexported.SubstRep f (Polysemy.Check.Arbitrary.Generic.ExistentialFor e)) r a, Generics.Kind.Unexported.SubstRep' f (Polysemy.Check.Arbitrary.Generic.ExistentialFor e) (Data.PolyKinded.LoT2 (Polysemy.Internal.Sem r) a)) => Polysemy.Check.Arbitrary.Generic.GArbitraryK e (Generics.Kind.Exists * f) r a
- Polysemy.Check.Arbitrary.Generic: instance (Polysemy.Check.Arbitrary.Generic.GArbitraryK e f r a, Polysemy.Check.Arbitrary.Generic.GArbitraryK e g r a) => Polysemy.Check.Arbitrary.Generic.GArbitraryK e (f GHC.Generics.:*: g) r a
- Polysemy.Check.Arbitrary.Generic: instance (Polysemy.Check.Arbitrary.Generic.GArbitraryK e f r a, Polysemy.Check.Arbitrary.Generic.GArbitraryK e g r a) => Polysemy.Check.Arbitrary.Generic.GArbitraryK e (f GHC.Generics.:+: g) r a
- Polysemy.Check.Arbitrary.Generic: instance (Test.QuickCheck.Arbitrary.CoArbitrary a, Polysemy.Check.Arbitrary.Generic.GArbitraryKTerm b) => Polysemy.Check.Arbitrary.Generic.GArbitraryKTerm (a -> b)
- Polysemy.Check.Arbitrary.Generic: instance Polysemy.Check.Arbitrary.AnyEff.ArbitraryEffOfType a r r => Polysemy.Check.Arbitrary.Generic.GArbitraryKTerm (Polysemy.Internal.Sem r a)
- Polysemy.Check.Arbitrary.Generic: instance Polysemy.Check.Arbitrary.Generic.GArbitraryK e (c1 Generics.Kind.:=>: (c2 Generics.Kind.:=>: f)) r a => Polysemy.Check.Arbitrary.Generic.GArbitraryK e ((c1 'Data.PolyKinded.Atom.:&: c2) Generics.Kind.:=>: f) r a
- Polysemy.Check.Arbitrary.Generic: instance Polysemy.Check.Arbitrary.Generic.GArbitraryK e GHC.Generics.U1 r a
- Polysemy.Check.Arbitrary.Generic: instance Polysemy.Check.Arbitrary.Generic.GArbitraryK e f r a => Polysemy.Check.Arbitrary.Generic.GArbitraryK e (('Data.PolyKinded.Atom.Kon ((GHC.Types.~~) a) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) Generics.Kind.:=>: f) r a
- Polysemy.Check.Arbitrary.Generic: instance Polysemy.Check.Arbitrary.Generic.GArbitraryK e f r a => Polysemy.Check.Arbitrary.Generic.GArbitraryK e ((('Data.PolyKinded.Atom.Kon (GHC.Types.~~) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) 'Data.PolyKinded.Atom.:@: 'Data.PolyKinded.Atom.Kon a) Generics.Kind.:=>: f) r a
- Polysemy.Check.Arbitrary.Generic: instance Polysemy.Check.Arbitrary.Generic.GArbitraryK e f r a => Polysemy.Check.Arbitrary.Generic.GArbitraryK e (GHC.Generics.M1 _1 _2 f) r a
- Polysemy.Check.Arbitrary.Generic: instance Polysemy.Check.Arbitrary.Generic.GArbitraryKTerm (Data.PolyKinded.Atom.Interpret f (Data.PolyKinded.LoT2 (Polysemy.Internal.Sem r) a)) => Polysemy.Check.Arbitrary.Generic.GArbitraryK e (Generics.Kind.Field f) r a
- Polysemy.Check.Arbitrary.Generic: instance Test.QuickCheck.Arbitrary.Arbitrary a => Polysemy.Check.Arbitrary.Generic.GArbitraryKTerm a
- Polysemy.Check.Arbitrary.Generic: instance forall k0 (e :: Polysemy.Internal.Kind.Effect) (b :: k0) (f :: Data.PolyKinded.LoT ((* -> *) -> * -> *) -> *) (r :: Polysemy.Internal.Kind.EffectRow) a. Polysemy.Check.Arbitrary.Generic.GArbitraryK e (('Data.PolyKinded.Atom.Kon ((GHC.Types.~~) b) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) Generics.Kind.:=>: f) r a
- Polysemy.Check.Arbitrary.Generic: instance forall k1 (e :: Polysemy.Internal.Kind.Effect) (b :: k1) (f :: Data.PolyKinded.LoT ((* -> *) -> * -> *) -> *) (r :: Polysemy.Internal.Kind.EffectRow) a. Polysemy.Check.Arbitrary.Generic.GArbitraryK e ((('Data.PolyKinded.Atom.Kon (GHC.Types.~~) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) 'Data.PolyKinded.Atom.:@: 'Data.PolyKinded.Atom.Kon b) Generics.Kind.:=>: f) r a
+ Polysemy.Check.Arbitrary: [SomeAction] :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a)) => e (Sem r) a -> SomeAction e r
+ Polysemy.Check.Arbitrary: [SomeEffOfType] :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a)) => e (Sem r) a -> SomeEffOfType r a
+ Polysemy.Check.Arbitrary: [SomeEff] :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a)) => e (Sem r) a -> SomeEff r
+ Polysemy.Check.Arbitrary: class ArbitraryAction (as :: [Type]) (e :: Effect) (r :: EffectRow)
+ Polysemy.Check.Arbitrary: class ArbitraryEff (es :: EffectRow) (r :: EffectRow)
+ Polysemy.Check.Arbitrary: class ArbitraryEffOfType (a :: Type) (es :: EffectRow) (r :: EffectRow)
+ Polysemy.Check.Arbitrary: class GArbitraryK (e :: Effect) (f :: LoT Effect -> Type) (r :: EffectRow) (a :: Type)
+ Polysemy.Check.Arbitrary: data SomeAction e (r :: EffectRow)
+ Polysemy.Check.Arbitrary: data SomeEff (r :: EffectRow)
+ Polysemy.Check.Arbitrary: data SomeEffOfType (r :: EffectRow) a
+ Polysemy.Check.Arbitrary: data family ExistentialFor (e :: Effect)
+ Polysemy.Check.Arbitrary: garbitraryk :: GArbitraryK e f r a => [Gen (f (LoT2 (Sem r) a))]
+ Polysemy.Check.Arbitrary: genEff :: forall e r a. (GenericK e, GArbitraryK e (RepK e) r a) => Gen (e (Sem r) a)
+ Polysemy.Check.Arbitrary: genSomeAction :: ArbitraryAction as e r => [Gen (SomeAction e r)]
+ Polysemy.Check.Arbitrary: genSomeEff :: ArbitraryEff es r => [Gen (SomeEff r)]
+ Polysemy.Check.Arbitrary: genSomeEffOfType :: ArbitraryEffOfType a es r => [Gen (SomeEffOfType r a)]
+ Polysemy.Check.Arbitrary: instance (Data.PolyKinded.Atom.Interpret c (Data.PolyKinded.LoT2 (Polysemy.Internal.Sem r) a), Polysemy.Check.Arbitrary.GArbitraryK e f r a) => Polysemy.Check.Arbitrary.GArbitraryK e (c Generics.Kind.:=>: f) r a
+ Polysemy.Check.Arbitrary: instance (GHC.Classes.Eq a, GHC.Show.Show a, GHC.Show.Show (e (Polysemy.Internal.Sem r) a), Polysemy.Check.Arbitrary.ArbitraryEffOfType a es r, Generics.Kind.GenericK e, Polysemy.Check.Arbitrary.GArbitraryK e (Generics.Kind.RepK e) r a, Test.QuickCheck.Arbitrary.CoArbitrary a, Polysemy.Internal.Union.Member e r) => Polysemy.Check.Arbitrary.ArbitraryEffOfType a (e : es) r
+ Polysemy.Check.Arbitrary: instance (Polysemy.Check.Arbitrary.ArbitraryAction as e r, GHC.Classes.Eq a, GHC.Show.Show a, Polysemy.Internal.Union.Member e r, GHC.Show.Show (e (Polysemy.Internal.Sem r) a), Generics.Kind.GenericK e, Test.QuickCheck.Arbitrary.CoArbitrary a, Polysemy.Check.Arbitrary.GArbitraryK e (Generics.Kind.RepK e) r a) => Polysemy.Check.Arbitrary.ArbitraryAction (a : as) e r
+ Polysemy.Check.Arbitrary: instance (Polysemy.Check.Arbitrary.ArbitraryEff es r, Polysemy.Check.Arbitrary.ArbitraryAction (Polysemy.Check.Arbitrary.TypesOf e) e r) => Polysemy.Check.Arbitrary.ArbitraryEff (e : es) r
+ Polysemy.Check.Arbitrary: instance (Polysemy.Check.Arbitrary.GArbitraryK e (Generics.Kind.Unexported.SubstRep f (Polysemy.Check.Arbitrary.ExistentialFor e)) r a, Generics.Kind.Unexported.SubstRep' f (Polysemy.Check.Arbitrary.ExistentialFor e) (Data.PolyKinded.LoT2 (Polysemy.Internal.Sem r) a)) => Polysemy.Check.Arbitrary.GArbitraryK e (Generics.Kind.Exists * f) r a
+ Polysemy.Check.Arbitrary: instance (Polysemy.Check.Arbitrary.GArbitraryK e f r a, Polysemy.Check.Arbitrary.GArbitraryK e g r a) => Polysemy.Check.Arbitrary.GArbitraryK e (f GHC.Generics.:*: g) r a
+ Polysemy.Check.Arbitrary: instance (Polysemy.Check.Arbitrary.GArbitraryK e f r a, Polysemy.Check.Arbitrary.GArbitraryK e g r a) => Polysemy.Check.Arbitrary.GArbitraryK e (f GHC.Generics.:+: g) r a
+ Polysemy.Check.Arbitrary: instance (Test.QuickCheck.Arbitrary.Arbitrary a, Polysemy.Check.Arbitrary.ArbitraryEff r r, Polysemy.Check.Arbitrary.ArbitraryEffOfType a r r) => Test.QuickCheck.Arbitrary.Arbitrary (Polysemy.Internal.Sem r a)
+ Polysemy.Check.Arbitrary: instance GHC.Show.Show (Polysemy.Check.Arbitrary.SomeAction e r)
+ Polysemy.Check.Arbitrary: instance GHC.Show.Show (Polysemy.Check.Arbitrary.SomeEff r)
+ Polysemy.Check.Arbitrary: instance GHC.Show.Show (Polysemy.Check.Arbitrary.SomeEffOfType r a)
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.ArbitraryAction '[] e r
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.ArbitraryEff '[] r
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.ArbitraryEffOfType a '[] r
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.GArbitraryK e (c1 Generics.Kind.:=>: (c2 Generics.Kind.:=>: f)) r a => Polysemy.Check.Arbitrary.GArbitraryK e ((c1 'Data.PolyKinded.Atom.:&: c2) Generics.Kind.:=>: f) r a
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.GArbitraryK e GHC.Generics.U1 r a
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.GArbitraryK e f r a => Polysemy.Check.Arbitrary.GArbitraryK e (('Data.PolyKinded.Atom.Kon ((GHC.Types.~~) a) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) Generics.Kind.:=>: f) r a
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.GArbitraryK e f r a => Polysemy.Check.Arbitrary.GArbitraryK e ((('Data.PolyKinded.Atom.Kon (GHC.Types.~~) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) 'Data.PolyKinded.Atom.:@: 'Data.PolyKinded.Atom.Kon a) Generics.Kind.:=>: f) r a
+ Polysemy.Check.Arbitrary: instance Polysemy.Check.Arbitrary.GArbitraryK e f r a => Polysemy.Check.Arbitrary.GArbitraryK e (GHC.Generics.M1 _1 _2 f) r a
+ Polysemy.Check.Arbitrary: instance Test.QuickCheck.Arbitrary.Arbitrary (Data.PolyKinded.Atom.Interpret f (Data.PolyKinded.LoT2 (Polysemy.Internal.Sem r) a)) => Polysemy.Check.Arbitrary.GArbitraryK e (Generics.Kind.Field f) r a
+ Polysemy.Check.Arbitrary: instance forall k0 (e :: Polysemy.Internal.Kind.Effect) (b :: k0) (f :: Data.PolyKinded.LoT ((* -> *) -> * -> *) -> *) (r :: Polysemy.Internal.Kind.EffectRow) a. Polysemy.Check.Arbitrary.GArbitraryK e (('Data.PolyKinded.Atom.Kon ((GHC.Types.~~) b) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) Generics.Kind.:=>: f) r a
+ Polysemy.Check.Arbitrary: instance forall k1 (e :: Polysemy.Internal.Kind.Effect) (b :: k1) (f :: Data.PolyKinded.LoT ((* -> *) -> * -> *) -> *) (r :: Polysemy.Internal.Kind.EffectRow) a. Polysemy.Check.Arbitrary.GArbitraryK e ((('Data.PolyKinded.Atom.Kon (GHC.Types.~~) 'Data.PolyKinded.Atom.:@: Data.PolyKinded.Atom.Var1) 'Data.PolyKinded.Atom.:@: 'Data.PolyKinded.Atom.Kon b) Generics.Kind.:=>: f) r a
+ Polysemy.Check.Arbitrary: type TypesOf (e :: Effect) = GTypesOf (RepK e)
+ Polysemy.Check.Arbitrary: type family GTypesOf (f :: LoT Effect -> Type) :: [Type]
Files
- ChangeLog.md +12/−0
- polysemy-check.cabal +2/−3
- src/Polysemy/Check.hs +17/−16
- src/Polysemy/Check/Arbitrary.hs +234/−3
- src/Polysemy/Check/Arbitrary/AnyEff.hs +0/−150
- src/Polysemy/Check/Arbitrary/Generic.hs +0/−100
- src/Polysemy/Check/Arbitrary/Generic.hs-boot +0/−20
- src/Polysemy/Check/Orphans.hs +4/−4
- test/CoverageSpec.hs +64/−0
ChangeLog.md view
@@ -1,5 +1,17 @@ # Changelog for polysemy-check +## v0.5.0.0 (2021-10-14)++- Flattened the module structure of `Polysemy.Check.Arbitrary`.+- Fixed a bug where `arbitraryActionFromRowOfType` would return bottom.+- Added an `Arbitrary` instance for `Sem r a`.+- Added tests to prove all generators have a uniform distribution for actions.+- `prepropLaw` now prints the actions it ran before and after your test.+- Changed the orphan `Show` instances for standard Polysemy effects to more+ easily be used for testing coverage.+- Added a `Show` instance for `SomeEffOfType`.+- (Internal) Removed the `GArbitraryKTerm` class+ ## v0.4.0.0 (2021-10-12) - `GArbitraryK` now supports actions that contain existential types.
polysemy-check.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: polysemy-check-version: 0.4.0.0+version: 0.5.0.0 synopsis: QuickCheck for Polysemy description: Please see the README on GitHub at <https://github.com/polysemy-research/polysemy-check#readme> category: Polysemy@@ -30,8 +30,6 @@ Generics.Kind.Unexported Polysemy.Check Polysemy.Check.Arbitrary- Polysemy.Check.Arbitrary.AnyEff- Polysemy.Check.Arbitrary.Generic Polysemy.Check.Orphans Polysemy.Internal.Union.Inject other-modules:@@ -71,6 +69,7 @@ main-is: Main.hs other-modules: CommutativeSpec+ CoverageSpec EquivSpec LawSpec WeirdEffectsSpec
src/Polysemy/Check.hs view
@@ -38,8 +38,6 @@ import Generics.Kind.TH (deriveGenericK) import Polysemy import Polysemy.Check.Arbitrary-import Polysemy.Check.Arbitrary.AnyEff-import Polysemy.Check.Arbitrary.Generic (GArbitraryK, ExistentialFor) import Polysemy.Check.Orphans () import Polysemy.Internal import Polysemy.Internal.Union.Inject (Inject, inject)@@ -124,20 +122,23 @@ SomeEff pre <- arbitraryActionFromRow @effs @r (m1, m2) <- g SomeEff post <- arbitraryActionFromRow @effs @r- pure $ ioProperty $ do- a1 <-- lower $ do- void $ send pre- a1 <- m1- r <- send post- pure (a1, r)- a2 <-- lower $ do- void $ send pre- a2 <- m2- r <- send post- pure (a2, r)- pure $ a1 === a2+ pure $+ counterexample ("before = " <> show pre) $+ counterexample ("after = " <> show post) $+ ioProperty $ do+ a1 <-+ lower $ do+ void $ send pre+ a1 <- m1+ r <- send post+ pure (a1, r)+ a2 <-+ lower $ do+ void $ send pre+ a2 <- m2+ r <- send post+ pure (a2, r)+ pure $ a1 === a2 ------------------------------------------------------------------------------
src/Polysemy/Check/Arbitrary.hs view
@@ -1,13 +1,108 @@+{-# OPTIONS_GHC -Wno-orphans #-}+ module Polysemy.Check.Arbitrary where -import Generics.Kind+import Control.Applicative (liftA2)+import Data.Kind (Type)+import GHC.Exts (type (~~))+import Generics.Kind hiding (SubstRep)+import Generics.Kind.Unexported import Polysemy-import Polysemy.Check.Arbitrary.AnyEff-import Polysemy.Check.Arbitrary.Generic+import Polysemy.Internal import Test.QuickCheck ------------------------------------------------------------------------------+-- | Data family for the instantiation of existential variables. If you want to+-- check properties for an effect @e@ that contains an existential type, the+-- synthesized 'Arbitrary' instance will instantiate all of @e@'s existential+-- types at @'ExistentialFor' e@.+--+-- @'ExistentialFor' e@ must have instances for every dictionary required by+-- @e@, and will likely require an 'Arbitrary' instance.+data family ExistentialFor (e :: Effect)+++------------------------------------------------------------------------------+-- | Given @'GArbitraryK' e ('RepK' e) r a@, this typeclass computes+-- generators for every well-typed constructor of @e (Sem r) a@. It is capable+-- of building generators for GADTs.+class GArbitraryK (e :: Effect) (f :: LoT Effect -> Type) (r :: EffectRow) (a :: Type) where+ garbitraryk :: [Gen (f (LoT2 (Sem r) a))]++instance GArbitraryK e U1 r a where+ garbitraryk = pure $ pure U1++instance (GArbitraryK e f r a, GArbitraryK e g r a) => GArbitraryK e (f :*: g) r a where+ garbitraryk = liftA2 (liftA2 (:*:)) (garbitraryk @e) (garbitraryk @e)++instance Arbitrary (Interpret f (LoT2 (Sem r) a)) => GArbitraryK e (Field f) r a where+ garbitraryk = pure $ fmap Field arbitrary++instance+ ( GArbitraryK e (SubstRep f (ExistentialFor e)) r a+ , SubstRep' f (ExistentialFor e) (LoT2 (Sem r) a)+ ) => GArbitraryK e (Exists Type f) r a where+ garbitraryk = fmap (Exists . unsubstRep @_ @_ @_ @(ExistentialFor e)) <$>+ garbitraryk @e @(SubstRep f (ExistentialFor e)) @r @a++instance (GArbitraryK e f r a, GArbitraryK e g r a) => GArbitraryK e (f :+: g) r a where+ garbitraryk = fmap (fmap L1) (garbitraryk @e @f)+ <> fmap (fmap R1) (garbitraryk @e @g)++instance (Interpret c (LoT2 (Sem r) a), GArbitraryK e f r a) => GArbitraryK e (c :=>: f) r a where+ garbitraryk = fmap (fmap SuchThat) (garbitraryk @e @f)++instance {-# OVERLAPPING #-} GArbitraryK e (c1 :=>: (c2 :=>: f)) r a+ => GArbitraryK e ((c1 ':&: c2) :=>: f) r a where+ garbitraryk =+ fmap+ ((\(SuchThat (SuchThat x)) -> SuchThat x)+ :: (c1 :=>: (c2 :=>: f)) x -> ((c1 ':&: c2) :=>: f) x)+ <$> garbitraryk @e++instance {-# OVERLAPPING #-} GArbitraryK e f r a => GArbitraryK e ('Kon ((~~) a) ':@: Var1 :=>: f) r a where+ garbitraryk = fmap SuchThat <$> garbitraryk @e @f++instance {-# OVERLAPPING #-} GArbitraryK e f r a => GArbitraryK e ('Kon (~~) ':@: Var1 ':@: 'Kon a :=>: f) r a where+ garbitraryk = fmap SuchThat <$> garbitraryk @e @f++instance {-# INCOHERENT #-} GArbitraryK e ('Kon ((~~) b) ':@: Var1 :=>: f) r a where+ garbitraryk = []++instance {-# INCOHERENT #-} GArbitraryK e ('Kon (~~) ':@: Var1 ':@: 'Kon b :=>: f) r a where+ garbitraryk = []++instance (GArbitraryK e f r a) => GArbitraryK e (M1 _1 _2 f) r a where+ garbitraryk = fmap M1 <$> garbitraryk @e++------------------------------------------------------------------------------++instance (Arbitrary a, ArbitraryEff r r, ArbitraryEffOfType a r r)+ => Arbitrary (Sem r a) where+ arbitrary =+ let terminal = [pure <$> arbitrary]+ in sized $ \n ->+ case n <= 1 of+ True -> oneof terminal+ False -> oneof $+ [ do+ SomeEffOfType e <- arbitraryActionFromRowOfType @r @r @a+ pure $ send e+ , do+ SomeEff e <- arbitraryActionFromRow @r @r+ k <- liftArbitrary $ scale (`div` 2) arbitrary+ pure $ send e >>= k+ ] <> terminal++------------------------------------------------------------------------------+-- | @genEff \@e \@r \@a@ gets a generator capable of producing every+-- well-typed GADT constructor of @e (Sem r) a@.+genEff :: forall e r a. (GenericK e, GArbitraryK e (RepK e) r a) => Gen (e (Sem r) a)+genEff = fmap toK $ oneof $ garbitraryk @e @(RepK e) @r+++------------------------------------------------------------------------------ -- | Generate any action for effect @e@. arbitraryAction :: forall e r@@ -45,4 +140,140 @@ => Gen (SomeEffOfType r a) -- ^ arbitraryActionFromRowOfType = oneof $ genSomeEffOfType @a @effs @r+++------------------------------------------------------------------------------+-- | Helper function for implementing 'GTypesOf'+type family GTypesOf (f :: LoT Effect -> Type) :: [Type] where+ GTypesOf (M1 _1 _2 f) = GTypesOf f+ GTypesOf (f :+: g) = Append (GTypesOf f) (GTypesOf g)+ GTypesOf (('Kon (~~) ':@: Var1 ':@: 'Kon a) :=>: f) = '[a]+ GTypesOf (('Kon ((~~) a) ':@: Var1) :=>: f) = '[a]+ -- Otherwise, we don't have any constraints on @a@, so we can instantiate it+ -- how we please. Just assume ().+ GTypesOf _1 = '[()]+++------------------------------------------------------------------------------+-- | @'TypesOf' e@ is a list of every type that can be bound via @e@'s actions.+--+-- For example, given:+--+-- @+-- data MyEffect m a where+-- Foo :: MyEffect m Int+-- Blah :: Bool -> MyEffect m String+-- @+--+-- the result of @'TypesOf' MyEffect@ is @'[Int, String]@.+type TypesOf (e :: Effect) = GTypesOf (RepK e)+++------------------------------------------------------------------------------+-- | @'SomeAction' e r@ is some action for effect @e@ in effect row @r@.+data SomeAction e (r :: EffectRow) where+ SomeAction+ :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a))+ => e (Sem r) a+ -- ^+ -> SomeAction e r+ -- ^++instance Show (SomeAction e r) where+ show (SomeAction ema) = show ema+++------------------------------------------------------------------------------+-- | @'SomeEff' r@ is some action for some effect in the effect row @r@.+data SomeEff (r :: EffectRow) where+ SomeEff+ :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a))+ => e (Sem r) a+ -- ^+ -> SomeEff r+ -- ^++instance Show (SomeEff r) where+ show (SomeEff sse) = show sse+++------------------------------------------------------------------------------+-- | @'SomeEff' r@ is some action for some effect in the effect row @r@.+data SomeEffOfType (r :: EffectRow) a where+ SomeEffOfType+ :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a))+ => e (Sem r) a+ -- ^+ -> SomeEffOfType r a+ -- ^++instance Show (SomeEffOfType r a) where+ show (SomeEffOfType sse) = show sse+++------------------------------------------------------------------------------+-- | @'ArbitraryEff' es r@ lets you randomly generate an action in any of+-- the effects @es@.+class ArbitraryEff (es :: EffectRow) (r :: EffectRow) where+ genSomeEff :: [Gen (SomeEff r)]++instance ArbitraryEff '[] r where+ genSomeEff = []++instance+ (ArbitraryEff es r, ArbitraryAction (TypesOf e) e r)+ => ArbitraryEff (e ': es) r+ where+ genSomeEff = fmap (fmap (\(SomeAction e) -> SomeEff e)) (genSomeAction @(TypesOf e) @e @r)+ <> genSomeEff @es @r+++------------------------------------------------------------------------------+-- | @'ArbitraryEffOfType' a es r@ lets you randomly generate an action in any of+-- the effects @es@ that produces type @a@.+class ArbitraryEffOfType (a :: Type) (es :: EffectRow) (r :: EffectRow) where+ genSomeEffOfType :: [Gen (SomeEffOfType r a)]++instance ArbitraryEffOfType a '[] r where+ genSomeEffOfType = []++instance+ ( Eq a+ , Show a+ , Show (e (Sem r) a)+ , ArbitraryEffOfType a es r+ , GenericK e+ , GArbitraryK e (RepK e) r a+ , CoArbitrary a+ , Member e r+ )+ => ArbitraryEffOfType a (e ': es) r+ where+ genSomeEffOfType+ = (fmap (SomeEffOfType @e @r . toK) <$> garbitraryk @e @(RepK e) @r)+ <> genSomeEffOfType @a @es @r+++------------------------------------------------------------------------------+-- | @'ArbitraryAction' as e r@ lets you randomly generate an action+-- producing any type in @as@ from the effect @e@.+class ArbitraryAction (as :: [Type]) (e :: Effect) (r :: EffectRow) where+ genSomeAction :: [Gen (SomeAction e r)]++instance ArbitraryAction '[] e r where+ genSomeAction = []++instance+ ( ArbitraryAction as e r+ , Eq a+ , Show a+ , Member e r+ , Show (e (Sem r) a)+ , GenericK e+ , CoArbitrary a+ , GArbitraryK e (RepK e) r a+ )+ => ArbitraryAction (a : as) e r+ where+ genSomeAction = (fmap SomeAction $ genEff @e @r @a) : genSomeAction @as @e @r
− src/Polysemy/Check/Arbitrary/AnyEff.hs
@@ -1,150 +0,0 @@-module Polysemy.Check.Arbitrary.AnyEff where--import Data.Kind (Type, Constraint)-import GHC.Exts (type (~~))-import Generics.Kind-import Polysemy-import Polysemy.Internal-import {-# SOURCE #-} Polysemy.Check.Arbitrary.Generic-import Test.QuickCheck------------------------------------------------------------------------------------ | Helper function for implementing 'GTypesOf'-type family GTypesOf (f :: LoT Effect -> Type) :: [Type] where- GTypesOf (M1 _1 _2 f) = GTypesOf f- GTypesOf (f :+: g) = Append (GTypesOf f) (GTypesOf g)- GTypesOf (('Kon (~~) ':@: Var1 ':@: 'Kon a) :=>: f) = '[a]- GTypesOf (('Kon ((~~) a) ':@: Var1) :=>: f) = '[a]- -- Otherwise, we don't have any constraints on @a@, so we can instantiate it- -- how we please. Just assume ().- GTypesOf _1 = '[()]------------------------------------------------------------------------------------ | @'TypesOf' e@ is a list of every type that can be bound via @e@'s actions.------ For example, given:------ @--- data MyEffect m a where--- Foo :: MyEffect m Int--- Blah :: Bool -> MyEffect m String--- @------ the result of @'TypesOf' MyEffect@ is @'[Int, String]@.-type TypesOf (e :: Effect) = GTypesOf (RepK e)------------------------------------------------------------------------------------ | A type family that expands to a 'GArbitraryK' constaint for every type in--- the first list.-type family ArbitraryForAll (e :: Effect) (as :: [Type]) (r :: EffectRow) :: Constraint where- ArbitraryForAll e '[] f = ()- ArbitraryForAll e (a ': as) r =- (Eq a, Show a, GArbitraryK e (RepK e) r a, ArbitraryForAll e as r)------------------------------------------------------------------------------------ | @'SomeAction' e r@ is some action for effect @e@ in effect row @r@.-data SomeAction e (r :: EffectRow) where- SomeAction- :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a))- => e (Sem r) a- -- ^- -> SomeAction e r- -- ^--instance Show (SomeAction e r) where- show (SomeAction ema) = show ema--instance Show (SomeEff r) where- show (SomeEff sse) = show sse------------------------------------------------------------------------------------ | @'SomeEff' r@ is some action for some effect in the effect row @r@.-data SomeEff (r :: EffectRow) where- SomeEff- :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a))- => e (Sem r) a- -- ^- -> SomeEff r- -- ^----------------------------------------------------------------------------------- | @'SomeEff' r@ is some action for some effect in the effect row @r@.-data SomeEffOfType (r :: EffectRow) a where- SomeEffOfType- :: (Member e r, Eq a, Show a, CoArbitrary a, Show (e (Sem r) a))- => e (Sem r) a- -- ^- -> SomeEffOfType r a- -- ^------------------------------------------------------------------------------------ | @'ArbitraryEff' es r@ lets you randomly generate an action in any of--- the effects @es@.-class ArbitraryEff (es :: EffectRow) (r :: EffectRow) where- genSomeEff :: [Gen (SomeEff r)]--instance ArbitraryEff '[] r where- genSomeEff = []--instance- (ArbitraryEff es r, ArbitraryAction (TypesOf e) e r)- => ArbitraryEff (e ': es) r- where- genSomeEff = fmap (fmap (\(SomeAction e) -> SomeEff e)) (genSomeAction @(TypesOf e) @e @r)- <> genSomeEff @es @r----------------------------------------------------------------------------------- | @'ArbitraryEffOfType' a es r@ lets you randomly generate an action in any of--- the effects @es@ that produces type @a@.-class ArbitraryEffOfType (a :: Type) (es :: EffectRow) (r :: EffectRow) where- genSomeEffOfType :: [Gen (SomeEffOfType r a)]--instance ArbitraryEffOfType a '[] r where- genSomeEffOfType = []--instance- ( Eq a- , Show a- , Show (e (Sem r) a)- , ArbitraryEffOfType a es r- , GenericK e- , GArbitraryK e (RepK e) r a- , CoArbitrary a- , Member e r- )- => ArbitraryEffOfType a (e ': es) r- where- genSomeEffOfType- = fmap SomeEffOfType (genEff @e @r @a)- : genSomeEffOfType @a @es @r------------------------------------------------------------------------------------ | @'ArbitraryAction' as e r@ lets you randomly generate an action--- producing any type in @as@ from the effect @e@.-class ArbitraryAction (as :: [Type]) (e :: Effect) (r :: EffectRow) where- genSomeAction :: [Gen (SomeAction e r)]--instance ArbitraryAction '[] e r where- genSomeAction = []--instance- ( ArbitraryAction as e r- , Eq a- , Show a- , Member e r- , Show (e (Sem r) a)- , GenericK e- , CoArbitrary a- , GArbitraryK e (RepK e) r a- )- => ArbitraryAction (a : as) e r- where- genSomeAction = (fmap SomeAction $ genEff @e @r @a) : genSomeAction @as @e @r-
− src/Polysemy/Check/Arbitrary/Generic.hs
@@ -1,100 +0,0 @@-module Polysemy.Check.Arbitrary.Generic where--import Control.Applicative (liftA2)-import Data.Kind (Type)-import GHC.Exts (type (~~))-import Generics.Kind hiding (SubstRep)-import Generics.Kind.Unexported-import Polysemy-import Polysemy.Check.Arbitrary.AnyEff-import Polysemy.Internal (send)-import Test.QuickCheck------------------------------------------------------------------------------------ | Data family for the instantiation of existential variables. If you want to--- check properties for an effect @e@ that contains an existential type, the--- synthesized 'Arbitrary' instance will instantiate all of @e@'s existential--- types at @'ExistentialFor' e@.------ @'ExistentialFor' e@ must have instances for every dictionary required by--- @e@, and will likely require an 'Arbitrary' instance.-data family ExistentialFor (e :: Effect)------------------------------------------------------------------------------------ | Given @'GArbitraryK' a ('RepK' e) r a@, this typeclass computes--- generators for every well-typed constructor of @e (Sem r) a@. It is capable--- of building generators for GADTs.-class GArbitraryK (e :: Effect) (f :: LoT Effect -> Type) (r :: EffectRow) (a :: Type) where- garbitraryk :: [Gen (f (LoT2 (Sem r) a))]--instance GArbitraryK e U1 r a where- garbitraryk = pure $ pure U1--instance (GArbitraryK e f r a, GArbitraryK e g r a) => GArbitraryK e (f :*: g) r a where- garbitraryk = liftA2 (liftA2 (:*:)) (garbitraryk @e) (garbitraryk @e)--instance GArbitraryKTerm (Interpret f (LoT2 (Sem r) a)) => GArbitraryK e (Field f) r a where- garbitraryk = pure $ fmap Field $ garbitrarykterm @(Interpret f (LoT2 (Sem r) a))--instance- ( GArbitraryK e (SubstRep f (ExistentialFor e)) r a- , SubstRep' f (ExistentialFor e) (LoT2 (Sem r) a)- ) => GArbitraryK e (Exists Type f) r a where- garbitraryk = fmap (Exists . unsubstRep @_ @_ @_ @(ExistentialFor e)) <$>- garbitraryk @e @(SubstRep f (ExistentialFor e)) @r @a--instance (GArbitraryK e f r a, GArbitraryK e g r a) => GArbitraryK e (f :+: g) r a where- garbitraryk = fmap (fmap L1) (garbitraryk @e @f)- <> fmap (fmap R1) (garbitraryk @e @g)--instance (Interpret c (LoT2 (Sem r) a), GArbitraryK e f r a) => GArbitraryK e (c :=>: f) r a where- garbitraryk = fmap (fmap SuchThat) (garbitraryk @e @f)--instance {-# OVERLAPPING #-} GArbitraryK e (c1 :=>: (c2 :=>: f)) r a- => GArbitraryK e ((c1 ':&: c2) :=>: f) r a where- garbitraryk =- fmap- ((\(SuchThat (SuchThat x)) -> SuchThat x)- :: (c1 :=>: (c2 :=>: f)) x -> ((c1 ':&: c2) :=>: f) x)- <$> garbitraryk @e--instance {-# OVERLAPPING #-} GArbitraryK e f r a => GArbitraryK e ('Kon ((~~) a) ':@: Var1 :=>: f) r a where- garbitraryk = fmap SuchThat <$> garbitraryk @e @f--instance {-# OVERLAPPING #-} GArbitraryK e f r a => GArbitraryK e ('Kon (~~) ':@: Var1 ':@: 'Kon a :=>: f) r a where- garbitraryk = fmap SuchThat <$> garbitraryk @e @f--instance {-# INCOHERENT #-} GArbitraryK e ('Kon ((~~) b) ':@: Var1 :=>: f) r a where- garbitraryk = []--instance {-# INCOHERENT #-} GArbitraryK e ('Kon (~~) ':@: Var1 ':@: 'Kon b :=>: f) r a where- garbitraryk = []--instance (GArbitraryK e f r a) => GArbitraryK e (M1 _1 _2 f) r a where- garbitraryk = fmap M1 <$> garbitraryk @e------------------------------------------------------------------------------------ | @genEff \@e \@r \@a@ gets a generator capable of producing every--- well-typed GADT constructor of @e (Sem r) a@.-genEff :: forall e r a. (GenericK e, GArbitraryK e (RepK e) r a) => Gen (e (Sem r) a)-genEff = fmap toK $ oneof $ garbitraryk @e @(RepK e) @r----class GArbitraryKTerm (t :: Type) where- garbitrarykterm :: Gen t--instance {-# OVERLAPPING #-} ArbitraryEffOfType a r r => GArbitraryKTerm (Sem r a) where- garbitrarykterm = do- SomeEffOfType act <- oneof $ genSomeEffOfType @a @r @r- pure $ send act--instance {-# OVERLAPPING #-} (CoArbitrary a, GArbitraryKTerm b) => GArbitraryKTerm (a -> b) where- garbitrarykterm = liftArbitrary garbitrarykterm--instance Arbitrary a => GArbitraryKTerm a where- garbitrarykterm = arbitrary-
− src/Polysemy/Check/Arbitrary/Generic.hs-boot
@@ -1,20 +0,0 @@-module Polysemy.Check.Arbitrary.Generic where--import Data.Kind (Type)-import Generics.Kind-import Test.QuickCheck-import Polysemy------------------------------------------------------------------------------------ | Given @'GArbitraryK' a ('RepK' (e m a))@, this typeclass computes--- generators for every well-typed constructor of @e m a@. It is capable of--- building generators for GADTs.-class GArbitraryK (e :: Effect) (f :: LoT Effect -> Type) (r :: EffectRow) (a :: Type) where- garbitraryk :: [Gen (f (LoT2 (Sem r) a))]----------------------------------------------------------------------------------- | @genEff \@e \@a \@m@ gets a generator capable of producing every--- well-typed GADT constructor of @e m a@.-genEff :: forall e r a. (GenericK e, GArbitraryK e (RepK e) r a) => Gen (e (Sem r) a)-
src/Polysemy/Check/Orphans.hs view
@@ -41,14 +41,14 @@ instance Show e => Show (Error e (Sem r) a) where show (Throw e2) = "Throw " <> show e2- show (Catch _ _) = "<Catch>"+ show (Catch _ _) = "Catch <m> <k>" instance Show (Reader e (Sem r) a) where show Ask = "Ask"- show (Local _ _) = "<Local>"+ show (Local _ _) = "Local <f> <m>" instance Show e => Show (Writer e (Sem r) a) where show (Tell e) = "Tell " <> show e- show (Listen _) = "<Listen>"- show (Pass _) = "<Pass>"+ show (Listen _) = "Listen <m>"+ show (Pass _) = "Pass <m>"
+ test/CoverageSpec.hs view
@@ -0,0 +1,64 @@+module CoverageSpec where++import Polysemy.Check+import Polysemy.Error+import Polysemy.Input+import Polysemy.Output+import Polysemy.State+import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck++data Test m a where+ Test1 :: Test m ()+ Test2 :: Int -> Test m ()+ Test3 :: Test m Int+ Test4 :: Test m Bool++deriving instance Show (Test m a)+deriveGenericK ''Test+++spec :: Spec+spec = do+ prop "arbitraryAction has a uniform probabilty" $ checkCoverage $ do+ e <- arbitraryAction @Test @'[Test]+ checkUniformProbability 4 e++ prop "arbitraryActionOfType has a uniform probability" $ checkCoverage $ do+ e <- arbitraryActionOfType @Test @()+ checkUniformProbability 2 e++ prop "arbitraryActionFromRow has a uniform probability (small row)" $ checkCoverage $ do+ e <- arbitraryActionFromRow @LittleRow @LittleRow+ checkUniformProbability 6 e++ prop "arbitraryActionFromRow has a uniform probability (large row)" $ checkCoverage $ do+ e <- arbitraryActionFromRow @BigRow @BigRow+ checkUniformProbability 10 e++ prop "arbitraryActionFromRowOfType has a uniform probability (Int)" $ checkCoverage $ do+ e <- arbitraryActionFromRowOfType @BigRow @BigRow @Int+ checkUniformProbability 5 e++ prop "arbitraryActionFromRowOfType has a uniform probability (())" $ checkCoverage $ do+ e <- arbitraryActionFromRowOfType @BigRow @BigRow @()+ checkUniformProbability 6 e+++type LittleRow = '[State Int, Test]+type BigRow = '[Error Int, Input Int, Output Int, State Int, Test]+++------------------------------------------------------------------------------+-- | @checkUniformProbability n a@ ensures that @a@ gets generated with+-- probability $\frac{1}{n}$.+checkUniformProbability :: (Applicative f, Show a) => Double -> a -> f Property+checkUniformProbability n e = pure $ cover (100 / n) True (constructor e) True+++------------------------------------------------------------------------------+-- | Get the constructor name (from a derived Show instance)+constructor :: Show a => a -> String+constructor = unwords . take 1 . words . show+