Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ghc-generic-random for 
openSUSE:Factory checked in at 2021-06-01 10:39:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-generic-random (Old)
 and      /work/SRC/openSUSE:Factory/.ghc-generic-random.new.1898 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ghc-generic-random"

Tue Jun  1 10:39:06 2021 rev:2 rq:896214 version:1.4.0.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-generic-random/ghc-generic-random.changes    
2021-05-05 20:40:34.410767055 +0200
+++ 
/work/SRC/openSUSE:Factory/.ghc-generic-random.new.1898/ghc-generic-random.changes
  2021-06-01 10:40:44.225147626 +0200
@@ -1,0 +2,10 @@
+Mon May 17 09:47:47 UTC 2021 - psim...@suse.com
+
+- Update generic-random to version 1.4.0.0.
+  # 1.4.0.0
+
+  - Add option to use only coherent instances
+  - Export `SetSized` and `SetUnsized`
+  - Drop compatibility with GHC 7
+
+-------------------------------------------------------------------

Old:
----
  generic-random-1.3.0.1.tar.gz

New:
----
  generic-random-1.4.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ghc-generic-random.spec ++++++
--- /var/tmp/diff_new_pack.i5UagY/_old  2021-06-01 10:40:44.649148347 +0200
+++ /var/tmp/diff_new_pack.i5UagY/_new  2021-06-01 10:40:44.649148347 +0200
@@ -19,7 +19,7 @@
 %global pkg_name generic-random
 %bcond_with tests
 Name:           ghc-%{pkg_name}
-Version:        1.3.0.1
+Version:        1.4.0.0
 Release:        0
 Summary:        Generic random generators for QuickCheck
 License:        MIT
@@ -31,7 +31,6 @@
 ExcludeArch:    %{ix86}
 %if %{with tests}
 BuildRequires:  ghc-deepseq-devel
-BuildRequires:  ghc-inspection-testing-devel
 %endif
 
 %description

++++++ generic-random-1.3.0.1.tar.gz -> generic-random-1.4.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/generic-random-1.3.0.1/CHANGELOG.md 
new/generic-random-1.4.0.0/CHANGELOG.md
--- old/generic-random-1.3.0.1/CHANGELOG.md     2020-03-22 00:08:58.000000000 
+0100
+++ new/generic-random-1.4.0.0/CHANGELOG.md     2001-09-09 03:46:40.000000000 
+0200
@@ -1,5 +1,11 @@
 https://github.com/Lysxia/generic-random/blob/master/changelog.md
 
+# 1.4.0.0
+
+- Add option to use only coherent instances
+- Export `SetSized` and `SetUnsized`
+- Drop compatibility with GHC 7
+
 # 1.3.0.1
 
 - Fix small typos in documentation.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/generic-random-1.3.0.1/generic-random.cabal 
new/generic-random-1.4.0.0/generic-random.cabal
--- old/generic-random-1.3.0.1/generic-random.cabal     2020-03-24 
03:48:16.000000000 +0100
+++ new/generic-random-1.4.0.0/generic-random.cabal     2001-09-09 
03:46:40.000000000 +0200
@@ -1,5 +1,5 @@
 name:                generic-random
-version:             1.3.0.1
+version:             1.4.0.0
 synopsis:            Generic random generators for QuickCheck
 description:
     Derive instances of @Arbitrary@ for QuickCheck,
@@ -23,7 +23,7 @@
 build-type:          Simple
 extra-source-files:  README.md CHANGELOG.md
 cabal-version:       >=1.10
-tested-with:         GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1, GHC == 8.2.1, 
GHC == 8.4.1, GHC == 8.6.1
+tested-with:         GHC == 8.0.1, GHC == 8.0.2, GHC == 8.2.1, GHC == 8.4.1, 
GHC == 8.6.1
 
 library
   hs-source-dirs:      src
@@ -33,7 +33,7 @@
     Generic.Random.Internal.Generic
     Generic.Random.Tutorial
   build-depends:
-    base >= 4.7 && < 5,
+    base >= 4.9 && < 5,
     QuickCheck
   default-language:    Haskell2010
   ghc-options: -Wall -fno-warn-name-shadowing
@@ -53,6 +53,17 @@
   type: exitcode-stdio-1.0
   default-language: Haskell2010
 
+test-suite coherence
+  hs-source-dirs:  test
+  main-is:         coherence.hs
+  build-depends:
+    base,
+    deepseq,
+    QuickCheck,
+    generic-random
+  type: exitcode-stdio-1.0
+  default-language: Haskell2010
+
 test-suite inspect
   hs-source-dirs:  test
   main-is:         Inspect.hs
@@ -63,5 +74,13 @@
     generic-random
   type: exitcode-stdio-1.0
   default-language: Haskell2010
-  if !impl(ghc >= 8.0.2)
+  if !flag(enable-inspect)
     buildable: False
+  else
+    build-depends: random < 1.2
+    -- TODO: this test fails with newer versions of random
+
+flag enable-inspect
+  description: Enable inspection tests
+  default: False
+  manual: True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/generic-random-1.3.0.1/src/Generic/Random/Internal/BaseCase.hs 
new/generic-random-1.4.0.0/src/Generic/Random/Internal/BaseCase.hs
--- old/generic-random-1.3.0.1/src/Generic/Random/Internal/BaseCase.hs  
2019-09-07 23:58:08.000000000 +0200
+++ new/generic-random-1.4.0.0/src/Generic/Random/Internal/BaseCase.hs  
2001-09-09 03:46:40.000000000 +0200
@@ -1,7 +1,6 @@
 {-# OPTIONS_HADDOCK not-home #-}
 
 {-# LANGUAGE AllowAmbiguousTypes #-}
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DefaultSignatures #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -13,9 +12,6 @@
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
-#if __GLASGOW_HASKELL__ < 710
-{-# LANGUAGE OverlappingInstances #-}
-#endif
 
 -- | Base case discovery.
 --
@@ -30,12 +26,7 @@
 module Generic.Random.Internal.BaseCase where
 
 import Control.Applicative
-#if __GLASGOW_HASKELL__ >= 800
 import Data.Proxy
-#endif
-#if __GLASGOW_HASKELL__ < 710
-import Data.Word
-#endif
 import GHC.Generics
 import GHC.TypeLits
 import Test.QuickCheck
@@ -298,7 +289,6 @@
 instance (y ~ 'Just 0) => GBCS U1 z y e where
   gbcs _ _ = pure U1
 
-#if __GLASGOW_HASKELL__ >= 800
 instance {-# INCOHERENT #-}
   ( TypeError
       (     'Text "Unrecognized Rep: "
@@ -312,7 +302,6 @@
   , Alternative (IfM y Weighted Proxy)
   ) => GBCS f z y e where
   gbcs = error "Type error"
-#endif
 
 class GBaseCaseSearch a z y e where
   gBaseCaseSearch :: prox y -> proxy '(z, e) -> IfM y Gen Proxy a
@@ -323,18 +312,3 @@
     (\(Weighted (Just (g, n))) -> choose (0, n-1) >>= fmap to . g)
     (\Proxy -> Proxy)
     (gbcs y z)
-
-#if __GLASGOW_HASKELL__ < 800
-data Proxy a = Proxy
-
-instance Functor Proxy where
-  fmap _ _ = Proxy
-
-instance Applicative Proxy where
-  pure _ = Proxy
-  _ <*> _ = Proxy
-
-instance Alternative Proxy where
-  empty = Proxy
-  _ <|> _ = Proxy
-#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/generic-random-1.3.0.1/src/Generic/Random/Internal/Generic.hs 
new/generic-random-1.4.0.0/src/Generic/Random/Internal/Generic.hs
--- old/generic-random-1.3.0.1/src/Generic/Random/Internal/Generic.hs   
2019-09-08 02:11:25.000000000 +0200
+++ new/generic-random-1.4.0.0/src/Generic/Random/Internal/Generic.hs   
2001-09-09 03:46:40.000000000 +0200
@@ -1,6 +1,6 @@
 {-# OPTIONS_HADDOCK not-home #-}
 
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -12,12 +12,9 @@
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeInType #-}
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
-#if __GLASGOW_HASKELL__ < 710
-{-# LANGUAGE OverlappingInstances #-}
-{-# LANGUAGE IncoherentInstances #-}
-#endif
 
 -- | Core implementation.
 --
@@ -31,27 +28,18 @@
 
 module Generic.Random.Internal.Generic where
 
-#if __GLASGOW_HASKELL__ < 710
-import Control.Applicative (Applicative(..))
-#endif
 import Control.Applicative (Alternative(..), liftA2)
-import Data.Coerce (coerce)
-#if __GLASGOW_HASKELL__ >= 800
+import Data.Coerce (Coercible, coerce)
 import Data.Kind (Type)
-#endif
+
 import Data.Proxy (Proxy(..))
-#if __GLASGOW_HASKELL__ >= 800
+import Data.Type.Bool (type (&&))
+import Data.Type.Equality (type (==))
+
 import GHC.Generics hiding (S, prec)
-#else
-import GHC.Generics hiding (S, Arity, prec)
-#endif
 import GHC.TypeLits (KnownNat, Nat, Symbol, type (+), natVal)
 import Test.QuickCheck (Arbitrary(..), Gen, choose, scale, sized, vectorOf)
 
-#if __GLASGOW_HASKELL__ < 800
-#define Type *
-#endif
-
 -- * Random generators
 
 -- | Pick a constructor with a given distribution, and fill its fields
@@ -107,7 +95,8 @@
 --
 -- > genericArbitraryG customGens (17 % 19 % ())
 --
--- where, for example to override generators for 'String' and 'Int' fields,
+-- where, the generators for 'String' and 'Int' fields are overridden as
+-- follows, for example:
 --
 -- @
 -- customGens :: Gen String ':+' Gen Int
@@ -118,9 +107,7 @@
 --
 -- === Note on multiple matches
 --
--- If the list contains multiple matching types for a field @x@ of type @a@
--- (i.e., either @Gen a@ or @'FieldGen' "x" a@), the generator for the first
--- match will be picked.
+-- Multiple generators may match a given field: the first will be chosen.
 genericArbitraryG
   :: (GArbitrary (SetGens genList UnsizedOpts) a)
   => genList
@@ -169,11 +156,7 @@
 type family Weights_ (f :: Type -> Type) :: Type where
   Weights_ (f :+: g) = Weights_ f :| Weights_ g
   Weights_ (M1 D _c f) = Weights_ f
-#if __GLASGOW_HASKELL__ >= 800
   Weights_ (M1 C ('MetaCons c _i _j) _f) = L c
-#else
-  Weights_ (M1 C _c _f) = L ""
-#endif
 
 data a :| b = N a Int b
 data L (c :: Symbol) = L
@@ -201,9 +184,6 @@
 -- @
 -- ((9 :: 'W' \"Leaf\") '%' (8 :: 'W' \"Node\") '%' ())
 -- @
---
--- Note: these annotations are only checked on GHC 8.0 or newer. They are
--- ignored on older GHCs.
 newtype W (c :: Symbol) = W Int deriving Num
 
 -- | A smart constructor to specify a custom distribution.
@@ -230,20 +210,10 @@
   Prec' (Weights a) = Prec (Weights_ (Rep a)) ()
   Prec' (a, Int, r) = Prec a r
 
--- | A synonym for @(~)@, except on GHC 7.10 and older, where it's the trivial
--- constraint. See note on 'W'.
-#if __GLASGOW_HASKELL__ >= 800
-class (a ~ b) => a ~. b
-instance (a ~ b) => a ~. b
-#else
-class a ~. b
-instance a ~. b
-#endif
-
 class WeightBuilder' w where
 
   -- | A binary constructor for building up trees of weights.
-  (%) :: (c ~. First' w) => W c -> Prec' w -> w
+  (%) :: (c ~ First' w) => W c -> Prec' w -> w
 
 instance WeightBuilder (Weights_ (Rep a)) => WeightBuilder' (Weights a) where
   w % prec = weights (w %. prec)
@@ -254,7 +224,7 @@
 class WeightBuilder a where
   type Prec a r
 
-  (%.) :: (c ~. First a) => W c -> Prec a r -> (a, Int, r)
+  (%.) :: (c ~ First a) => W c -> Prec a r -> (a, Int, r)
 
 infixr 1 %
 
@@ -298,10 +268,52 @@
 
 
 -- | Type-level options for 'GArbitrary'.
-newtype Options (s :: Sizing) (genList :: Type) = Options
+--
+-- Note: it is recommended to avoid referring to the 'Options' type
+-- explicitly in code, as the set of options may change in the future.
+-- Instead, use the provided synonyms ('UnsizedOpts', 'SizedOpts', 
'SizedOptsDef')
+-- and the setter 'SetOptions' (abbreviated as @('<+')@).
+newtype Options (c :: Coherence) (s :: Sizing) (genList :: Type) = Options
   { _generators :: genList
   }
 
+-- | Setter for 'Options'.
+--
+-- This subsumes the other setters: 'SetSized', 'SetUnsized', 'SetGens'.
+--
+-- @since 1.4.0.0
+type family SetOptions (x :: k) (o :: Type) :: Type
+type instance SetOptions (s :: Sizing) (Options c _s g) = Options c s g
+type instance SetOptions (c :: Coherence) (Options _c s g) = Options c s g
+type instance SetOptions (g :: Type) (Options c s _g) = Options c s g
+
+-- | Infix flipped synonym for 'Options'.
+--
+-- @since 1.4.0.0
+type (<+) o x = SetOptions x o
+infixl 1 <+
+
+
+type UnsizedOpts = Options 'INCOHERENT 'Unsized ()
+type SizedOpts = Options 'INCOHERENT 'Sized ()
+type SizedOptsDef = Options 'INCOHERENT 'Sized (Gen1 [] :+ ())
+
+-- | Like 'UnsizedOpts', but using coherent instances by default.
+--
+-- @since 1.4.0.0
+type CohUnsizedOpts = Options 'COHERENT 'Unsized ()
+
+-- | Like 'SizedOpts', but using coherent instances by default.
+--
+-- @since 1.4.0.0
+type CohSizedOpts = Options 'COHERENT 'Sized ()
+
+-- | Coerce an 'Options' value between types with the same representation.
+--
+-- @since 1.4.0.0
+setOpts :: forall x o. (Coercible o (SetOptions x o)) => o -> SetOptions x o
+setOpts = coerce
+
 -- | Default options for unsized generators.
 unsizedOpts :: UnsizedOpts
 unsizedOpts = Options ()
@@ -314,23 +326,90 @@
 sizedOptsDef :: SizedOptsDef
 sizedOptsDef = Options (Gen1 listOf' :+ ())
 
+-- | Like 'unsizedOpts', but using coherent instances by default.
+cohUnsizedOpts :: CohUnsizedOpts
+cohUnsizedOpts = Options ()
+
+-- | Like 'sizedOpts' but using coherent instances by default.
+cohSizedOpts :: CohSizedOpts
+cohSizedOpts = Options ()
 
--- | Whether to decrease the size parameter before generating fields.
-data Sizing = Sized | Unsized
 
-type UnsizedOpts = Options 'Unsized ()
-type SizedOpts = Options 'Sized ()
-type SizedOptsDef = Options 'Sized (Gen1 [] :+ ())
+-- | Whether to decrease the size parameter before generating fields.
+--
+-- The 'Sized' option makes the size parameter decrease in the following way:
+-- - Constructors with one field decrease the size parameter by 1 to generate
+--   that field.
+-- - Constructors with more than one field split the size parameter among all
+--   fields; the size parameter is rounded down to then be divided equally.
+data Sizing
+  = Sized     -- ^ Decrease the size parameter when running generators for 
fields
+  | Unsized   -- ^ Don't touch the size parameter
 
 type family SizingOf opts :: Sizing
-type instance SizingOf (Options s _g) = s
+type instance SizingOf (Options _c s _g) = s
+
+type family SetSized (o :: Type) :: Type
+type instance SetSized (Options c s g) = Options c 'Sized g
 
-setSized :: Options s g -> Options 'Sized g
+type family SetUnsized (o :: Type) :: Type
+type instance SetUnsized (Options c s g) = Options c 'Unsized g
+
+setSized :: Options c s g -> Options c 'Sized g
 setSized = coerce
 
-setUnsized :: Options s g -> Options 'Unsized g
+setUnsized :: Options c s g -> Options c 'Unsized g
 setUnsized = coerce
 
+
+-- | For custom generators to work with parameterized types, incoherent
+-- instances must be used internally.
+-- In practice, the resulting behavior is what users want 100% of the time,
+-- so you should forget this option even exists.
+--
+-- === __Details__
+--
+-- The default configuration of generic-random does a decent job if
+-- we trust GHC implements precisely the instance resolution algorithm as
+-- described in the GHC manual:
+--
+-- - 
https://downloads.haskell.org/ghc/latest/docs/html/users_guide/glasgow_exts.html#overlapping-instances
+--
+-- While that assumption holds in practice, it is overly context-dependent
+-- (to know the context leading to a particular choice, we must replay the
+-- whole resolution algorithm).
+-- In particular, this algorithm may find one solution, but it is not
+-- guaranteed to be unique: the behavior of the program is dependent on
+-- implementation details.
+--
+-- An notable property to consider of an implicit type system (such as type
+-- classes) is coherence: the behavior of the program is stable under
+-- specialization.
+--
+-- This sounds nice on paper, but actually leads to surprising behavior for
+-- generic implementations with parameterized types, such as generic-random.
+--
+-- To address that, the coherence property can be relaxd by users, by
+-- explicitly allowing some custom generators to be chosen incoherently. With
+-- appropriate precautions, it is possible to ensure a weaker property which
+-- nevertheless helps keep type inference predictable: when a solution is
+-- found, it is unique.
+-- (This is assuredly weaker, i.e., is not stable under specialization.)
+--
+-- @since 1.4.0.0
+data Coherence
+  = INCOHERENT  -- ^ Match custom generators incoherently.
+  | COHERENT
+    -- ^ Match custom generators coherently by default
+    -- (can be manually bypassed with 'Incoherent').
+
+type family CoherenceOf (o :: Type) :: Coherence
+type instance CoherenceOf (Options c _s _g) = c
+
+-- | Match this generator incoherently when the 'INCOHERENT' option is set.
+newtype Incoherent g = Incoherent g
+
+
 -- | Heterogeneous list of generators.
 data a :+ b = a :+ b
 
@@ -338,25 +417,32 @@
 
 
 type family GeneratorsOf opts :: Type
-type instance GeneratorsOf (Options _s g) = g
+type instance GeneratorsOf (Options _c _s g) = g
 
 class HasGenerators opts where
   generators :: opts -> GeneratorsOf opts
 
-instance HasGenerators (Options s g) where
+instance HasGenerators (Options c s g) where
   generators = _generators
 
-setGenerators :: genList -> Options s g0 -> Options s genList
+-- | Define the set of custom generators.
+--
+-- Note: for recursive types which can recursively appear inside lists or other
+-- containers, you may want to include a custom generator to decrease the size
+-- when generating such containers.
+--
+-- See also the Note about lists in "Generic.Random.Tutorial#notelists".
+setGenerators :: genList -> Options c s g0 -> Options c s genList
 setGenerators gens (Options _) = Options gens
 
-
 type family SetGens (g :: Type) opts
-type instance SetGens g (Options s _g) = Options s g
+type instance SetGens g (Options c s _g) = Options c s g
+
 
-#if __GLASGOW_HASKELL__ >= 800
 -- | Custom generator for record fields named @s@.
 --
--- /Available only for @base >= 4.9@ (@GHC >= 8.0.1@)./
+-- If there is a field named @s@ with a different type,
+-- this will result in a type error.
 newtype FieldGen (s :: Symbol) a = FieldGen { unFieldGen :: Gen a }
 
 -- | 'FieldGen' constructor with the field name given via a proxy.
@@ -364,20 +450,20 @@
 fieldGen _ = FieldGen
 
 -- | Custom generator for the @i@-th field of the constructor named @c@.
---
--- /Available only for @base >= 4.9@ (@GHC >= 8.0.1@)./
+-- Fields are 0-indexed.
 newtype ConstrGen (c :: Symbol) (i :: Nat) a = ConstrGen { unConstrGen :: Gen 
a }
 
 -- | 'ConstrGen' constructor with the constructor name given via a proxy.
 constrGen :: proxy '(c, i) -> Gen a -> ConstrGen c i a
 constrGen _ = ConstrGen
-#endif
 
 -- | Custom generators for \"containers\" of kind @Type -> Type@, parameterized
 -- by the generator for \"contained elements\".
 --
 -- A custom generator @'Gen1' f@ will be used for any field whose type has the
--- form @f x@, requiring a generator of @x@.
+-- form @f x@, requiring a generator of @x@. The generator for @x@ will be
+-- constructed using the list of custom generators if possible, otherwise
+-- an instance @Arbitrary x@ will be required.
 newtype Gen1 f = Gen1 { unGen1 :: forall a. Gen a -> Gen (f a) }
 
 -- | Custom generators for unary type constructors that are not \"containers\",
@@ -387,6 +473,7 @@
 -- form @f x@.
 newtype Gen1_ f = Gen1_ { unGen1_ :: forall a. Gen (f a) }
 
+
 -- | An alternative to 'vectorOf' that divides the size parameter by the
 -- length of the list.
 vectorOf' :: Int -> Gen a -> Gen [a]
@@ -496,12 +583,14 @@
 
 instance
   ( HasGenerators opts
-  , ArbitraryOr gs () gs '(c, i, Name d) a
-  , gs ~ GeneratorsOf opts )
+  , FindGen 'Shift ('S gs coh '(c, i, Name d)) () gs a
+  , gs ~ GeneratorsOf opts
+  , coh ~ CoherenceOf opts )
   => GAProduct' c i opts (S1 d (K1 _k a)) where
-  gaProduct' _ opts = fmap (M1 . K1) (arbitraryOr sel gs () gs)
+  gaProduct' _ opts = fmap (M1 . K1) (findGen (is, s, gs) () gs)
     where
-      sel = Proxy :: Proxy '(c, i, Name d)
+      is = Proxy :: Proxy 'Shift
+      s = Proxy :: Proxy ('S gs coh '(c, i, Name d))
       gs = generators opts
   {-# INLINE gaProduct' #-}
 
@@ -517,8 +606,8 @@
   Arity (f :*: g) = Arity f + Arity g
   Arity (M1 _i _c _f) = 1
 
--- | Given a list of custom generators @gs@, find one that applies, or use
--- @Arbitrary a@ by default.
+-- | Given a list of custom generators @g :+ gs@, find one that applies,
+-- or use @Arbitrary a@ by default.
 --
 -- @g@ and @gs@ follow this little state machine:
 --
@@ -528,72 +617,148 @@
 -- >          (), g :+ gs | g, gs
 -- >          (),      g  | g, () when g is not (_ :+ _)
 -- >      g :+ h,      gs | g, h :+ gs
--- >       Gen a,      gs | END if matching, else (), gs
+-- >       Gen a,      gs | END if g matches, else ((), gs)
 -- >  FieldGen a,      gs | idem
 -- > ConstrGen a,      gs | idem
 -- >      Gen1 a,      gs | idem
 -- >     Gen1_ a,      gs | idem
-class ArbitraryOr (fullGenList :: Type) (g :: Type) (gs :: Type)
-        (sel :: (Maybe Symbol, Nat, Maybe Symbol)) a where
-  arbitraryOr :: proxy sel -> fullGenList -> g -> gs -> Gen a
+class FindGen (i :: AInstr) (s :: AStore) (g :: Type) (gs :: Type) (a :: Type) 
where
+  findGen :: (Proxy i, Proxy s, FullGenListOf s) -> g -> gs -> Gen a
+
+data AInstr = Shift | Match Coherence | MatchCoh Bool
+data AStore = S Type Coherence ASel
+
+type ASel = (Maybe Symbol, Nat, Maybe Symbol)
+
+iShift :: Proxy 'Shift
+iShift = Proxy
+
+type family FullGenListOf (s :: AStore) :: Type where
+  FullGenListOf ('S fg _coh _sel) = fg
+
+type family ACoherenceOf (s :: AStore) :: Coherence where
+  ACoherenceOf ('S _fg coh _sel) = coh
+
+type family ASelOf (s :: AStore) :: ASel where
+  ASelOf ('S _fg _coh sel) = sel
 
 -- | All candidates have been exhausted
-instance Arbitrary a => ArbitraryOr fg () () sel a where
-  arbitraryOr _ _ _ _ = arbitrary
-  {-# INLINE arbitraryOr #-}
+instance Arbitrary a => FindGen 'Shift s () () a where
+  findGen _ _ _ = arbitrary
+  {-# INLINEABLE findGen #-}
 
 -- | Examine the next candidate
-instance ArbitraryOr fg b g sel a => ArbitraryOr fg () (b :+ g) sel a where
-  arbitraryOr sel fg () (b :+ gens) = arbitraryOr sel fg b gens
-  {-# INLINE arbitraryOr #-}
+instance FindGen 'Shift s b g a => FindGen 'Shift s () (b :+ g) a where
+  findGen p () (b :+ gens) = findGen p b gens
+  {-# INLINEABLE findGen #-}
 
 -- | Examine the last candidate (@g@ is not of the form @_ :+ _@)
-instance {-# OVERLAPS #-} ArbitraryOr fg g () sel a => ArbitraryOr fg () g sel 
a where
-  arbitraryOr sel fg () g = arbitraryOr sel fg g ()
+instance {-# OVERLAPS #-} FindGen 'Shift s g () a => FindGen 'Shift s () g a 
where
+  findGen p () g = findGen p g ()
 
 -- | This can happen if the generators form a tree rather than a list, for 
whatever reason.
-instance ArbitraryOr fg g (h :+ gs) sel a => ArbitraryOr fg (g :+ h) gs sel a 
where
-  arbitraryOr sel fg (g :+ h) gs = arbitraryOr sel fg g (h :+ gs)
+instance FindGen 'Shift s g (h :+ gs) a => FindGen 'Shift s (g :+ h) gs a where
+  findGen p (g :+ h) gs = findGen p g (h :+ gs)
+
+instance FindGen ('Match 'INCOHERENT) s g gs a => FindGen 'Shift s (Incoherent 
g) gs a where
+  findGen (_, s, fg) (Incoherent g) = findGen (im, s, fg) g where
+    im = Proxy :: Proxy ('Match 'INCOHERENT)
+
+-- | If none of the above matches, then @g@ should be a simple generator,
+-- and we test whether it matches the type @a@.
+instance {-# OVERLAPPABLE #-} FindGen ('Match (ACoherenceOf s)) s g gs a
+  => FindGen 'Shift s g gs a where
+  findGen (_, s, fg) = findGen (im, s, fg) where
+    im = Proxy :: Proxy ('Match (ACoherenceOf s))
+
+-- INCOHERENT
 
 -- | None of the INCOHERENT instances match, discard the candidate @g@ and look
 -- at the rest of the list @gs@.
-instance {-# OVERLAPPABLE #-} ArbitraryOr fg () gs sel a => ArbitraryOr fg g 
gs sel a where
-  arbitraryOr sel fg _ = arbitraryOr sel fg ()
+instance FindGen 'Shift s () gs a
+  => FindGen ('Match 'INCOHERENT) s _g gs a where
+  findGen (_, s, fg) _ = findGen (iShift, s, fg) () where
 
 -- | Matching custom generator for @a@.
-instance {-# INCOHERENT #-} ArbitraryOr fg (Gen a) g sel a where
-  arbitraryOr _ _ gen _ = gen
-  {-# INLINE arbitraryOr #-}
+instance {-# INCOHERENT #-} FindGen ('Match 'INCOHERENT) s (Gen a) gs a where
+  findGen _ gen _ = gen
+  {-# INLINEABLE findGen #-}
+
+-- | Matching custom generator for non-container @f@.
+instance {-# INCOHERENT #-} FindGen ('Match 'INCOHERENT) s (Gen1_ f) gs (f a) 
where
+  findGen _ (Gen1_ gen) _ = gen
+
+-- | Matching custom generator for container @f@. Start the search for 
containee @a@,
+-- discarding field information.
+instance {-# INCOHERENT #-} FindGen 'Shift ('S fg coh DummySel) () fg a
+  => FindGen ('Match 'INCOHERENT) ('S fg coh _sel) (Gen1 f) gs (f a) where
+  findGen (_, _, fg) (Gen1 gen) _ = gen (findGen (iShift, s, fg) () fg) where
+    s  = Proxy :: Proxy ('S fg coh DummySel)
+
+type DummySel = '( 'Nothing, 0, 'Nothing)
 
-#if __GLASGOW_HASKELL__ >= 800
 -- | Matching custom generator for field @s@.
-instance {-# INCOHERENT #-} (a ~ a') => ArbitraryOr fg (FieldGen s a) g '(con, 
i, 'Just s) a' where
-  arbitraryOr _ _ (FieldGen gen) _ = gen
-  {-# INLINE arbitraryOr #-}
+instance {-# INCOHERENT #-} (a ~ a')
+  => FindGen ('Match 'INCOHERENT) ('S _fg _coh '(con, i, 'Just s)) (FieldGen s 
a) gs a' where
+  findGen _ (FieldGen gen) _ = gen
+  {-# INLINEABLE findGen #-}
 
 -- | Matching custom generator for @i@-th field of constructor @c@.
-instance {-# INCOHERENT #-} (a ~ a') => ArbitraryOr fg (ConstrGen c i a) g '( 
'Just c, i, s) a' where
-  arbitraryOr _ _ (ConstrGen gen) _ = gen
-  {-# INLINE arbitraryOr #-}
+instance {-# INCOHERENT #-} (a ~ a')
+  => FindGen ('Match 'INCOHERENT) ('S _fg _coh '( 'Just c, i, s)) (ConstrGen c 
i a) gs a' where
+  findGen _ (ConstrGen gen) _ = gen
+  {-# INLINEABLE findGen #-}
 
 -- | Get the name contained in a 'Meta' tag.
 type family Name (d :: Meta) :: Maybe Symbol
 type instance Name ('MetaSel mn su ss ds) = mn
 type instance Name ('MetaCons n _f _s) = 'Just n
-#else
-type Name d = (Nothing :: Maybe Symbol)
-#endif
-
--- | Matching custom generator for non-container @f@
-instance {-# INCOHERENT #-} ArbitraryOr fg (Gen1_ f) g sel (f a) where
-  arbitraryOr _ _ (Gen1_ gen) _ = gen
 
--- | Matching custom generator for container @f@. Start the search for 
containee @a@,
--- discarding field information.
-instance {-# INCOHERENT #-} ArbitraryOr fg () fg '( 'Nothing, 0, 'Nothing) a
-  => ArbitraryOr fg (Gen1 f) g sel (f a) where
-  arbitraryOr _ fg (Gen1 gen) _ = gen (arbitraryOr noSel fg () fg)
-    where noSel = Proxy :: Proxy '( 'Nothing, 0, 'Nothing)
+-- COHERENT
+
+-- Use a type famaily to do the matching coherently.
+instance FindGen ('MatchCoh (Matches (ASelOf s) g a)) s g gs a
+  => FindGen ('Match 'COHERENT) s g gs a where
+  findGen (_, s, fg) = findGen (im, s, fg) where
+    im = Proxy :: Proxy ('MatchCoh (Matches (ASelOf s) g a))
+
+type family Matches (s :: ASel) (g :: Type) (a :: Type) :: Bool where
+  Matches _sel (Gen b) a = b == a
+  Matches _sel (Gen1_ f) (f a) = 'True
+  Matches _sel (Gen1_ f) a = 'False
+  Matches _sel (Gen1 f) (f a) = 'True
+  Matches _sel (Gen1 f) a = 'False
+  Matches '(_c, i,  s) (FieldGen s1 b) a = s == 'Just s1 && b == a
+  Matches '( c, i, _s) (ConstrGen c1 j b) a = c == 'Just c1 && i == j && b == a
+
+-- If there is no match, skip and shift.
+instance FindGen 'Shift s () gs a => FindGen ('MatchCoh 'False) s _g gs a where
+  findGen (_, s, fg) _ = findGen (iShift, s, fg) () where
+
+-- If there is a match, the search terminates
+
+instance (a ~ a') => FindGen ('MatchCoh 'True) s (Gen a) gs a' where
+  findGen _ g _ = g
+
+instance (f x ~ a') => FindGen ('MatchCoh 'True) s (Gen1_ f) gs a' where
+  findGen _ (Gen1_ g) _ = g
+
+instance (f x ~ a', FindGen 'Shift ('S fg coh DummySel) () fg x)
+  => FindGen ('MatchCoh 'True) ('S fg coh _sel) (Gen1 f) gs a' where
+  findGen (_, _, fg) (Gen1 gen) _ = gen (findGen (iShift, s, fg) () fg) where
+    s  = Proxy :: Proxy ('S fg coh DummySel)
+
+-- | Matching custom generator for field @s@.
+instance (a ~ a')
+  => FindGen ('MatchCoh 'True) s (FieldGen sn a) gs a' where
+  findGen _ (FieldGen gen) _ = gen
+
+-- | Matching custom generator for @i@-th field of constructor @c@.
+instance (a ~ a')
+  => FindGen ('MatchCoh 'True) s (ConstrGen c i a) gs a' where
+  findGen _ (ConstrGen gen) _ = gen
+
+--
 
 newtype Weighted a = Weighted (Maybe (Int -> Gen a, Int))
   deriving Functor
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/generic-random-1.3.0.1/src/Generic/Random/Tutorial.hs 
new/generic-random-1.4.0.0/src/Generic/Random/Tutorial.hs
--- old/generic-random-1.3.0.1/src/Generic/Random/Tutorial.hs   2020-03-22 
00:11:14.000000000 +0100
+++ new/generic-random-1.4.0.0/src/Generic/Random/Tutorial.hs   2001-09-09 
03:46:40.000000000 +0200
@@ -40,7 +40,7 @@
 --
 -- The distribution of constructors can be specified as
 -- a special list of /weights/ in the same order as the data type definition.
--- This assigns to each constructor a probability proportional to its weight;
+-- This assigns to each constructor a probability @p_C@ proportional to its 
weight @weight_C@;
 -- in other words, @p_C = weight_C / sumOfWeights@.
 --
 -- The list of weights is built up with the @('%')@ operator as a cons, and 
using
@@ -49,7 +49,7 @@
 --
 -- == Uniform distribution
 --
--- You can specify the uniform distribution (all weights equal) with 'uniform'.
+-- You can specify the uniform distribution (all weights equal to 1) with 
'uniform'.
 -- ('genericArbitraryU' is available as a shorthand for
 -- @'genericArbitrary' 'uniform'@.)
 --
@@ -58,22 +58,19 @@
 --
 -- == Typed weights
 --
--- /GHC 8.0.1 and above only (base ??? 4.9)./ For compatibility, the 
annotations
--- are still allowed on older GHC versions, but ignored.
---
 -- The weights actually have type @'W' \"ConstructorName\"@ (just a newtype
 -- around 'Int'), so that you can annotate a weight with its corresponding
 -- constructor. The constructors must appear in the same order as in the
 -- original type definition.
 --
--- This will type-check.
+-- This will type-check:
 --
 -- @
 -- ((x :: 'W' \"Leaf\") '%' (y :: 'W' \"Node\") '%' ()) :: 'Weights' (Tree a)
 -- ( x              '%' (y :: 'W' \"Node\") '%' ()) :: 'Weights' (Tree a)
 -- @
 --
--- This will not.
+-- This will not:
 --
 -- @
 -- ((x :: 'W' \"Node\") '%' y '%' ()) :: 'Weights' (Tree a)
@@ -88,8 +85,8 @@
 -- As mentioned earlier, one must be careful with recursive types
 -- to avoid producing extremely large values.
 -- The alternative generator 'genericArbitraryRec' decreases the size
--- parameter at every call to keep values at reasonable sizes,
--- to be used together with 'withBaseCase'.
+-- parameter at every call to keep values at reasonable sizes.
+-- It is to be used together with 'withBaseCase'.
 --
 -- For example, we may provide a base case consisting of only @Leaf@:
 --
@@ -155,7 +152,7 @@
 -- where the depth of a constructor is defined as @1 + max(0, depths of 
fields)@,
 -- e.g., @Leaf ()@ has depth 2.
 --
--- == Note about lists
+-- == Note about lists #notelists#
 --
 -- The @Arbitrary@ instance for lists can be problematic for this way
 -- of implementing recursive sized generators, because they make a lot of
@@ -283,10 +280,7 @@
 -- Suggestions to add more modifiers or otherwise improve this tutorial are 
welcome!
 -- <https://github.com/Lysxia/generic-random/issues The issue tracker is this 
way.>
 
-{-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ >= 800
 {-# OPTIONS_GHC -Wno-unused-imports #-}
-#endif
 
 module Generic.Random.Tutorial () where
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/generic-random-1.3.0.1/src/Generic/Random.hs 
new/generic-random-1.4.0.0/src/Generic/Random.hs
--- old/generic-random-1.3.0.1/src/Generic/Random.hs    2019-09-07 
22:53:33.000000000 +0200
+++ new/generic-random-1.4.0.0/src/Generic/Random.hs    2001-09-09 
03:46:40.000000000 +0200
@@ -27,7 +27,7 @@
 -- - "Generic.Random.Tutorial"
 -- - http://blog.poisson.chat/posts/2018-01-05-generic-random-tour.html
 
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE ExplicitNamespaces #-}
 
 module Generic.Random
   (
@@ -122,13 +122,37 @@
   , uniform
 
     -- * Custom generators
+
+    -- | Custom generators can be specified in a list constructed with 
@(':+')@,
+    -- and passed to functions such as 'genericArbitraryG' to override how 
certain
+    -- fields are generated.
+    --
+    -- Example:
+    --
+    -- @
+    -- customGens :: Gen String ':+' Gen Int
+    -- customGens =
+    --   (filter (/= '\NUL') '<$>' arbitrary) ':+'
+    --   (getNonNegative '<$>' arbitrary)
+    -- @
+    --
+    -- There are also different types of generators, other than 'Gen', 
providing
+    -- more ways to select the fields the generator than by simply comparing 
types:
+    --
+    -- - @'Gen' a@: override fields of type @a@;
+    -- - @'Gen1' f@: override fields of type @f x@ for some @x@, requiring a 
generator for @x@;
+    -- - @'Gen1_' f@: override fields of type @f x@ for some @x@, __not__ 
requiring a generator for @x@;
+    -- - @'FieldGen' s a@: override record fields named @s@, which must have 
type @a@;
+    -- - @'ConstrGen' c i a@: override the field at index @i@ of constructor 
@c@,
+    --   which must have type @a@ (0-indexed);
+    --
+    -- Multiple generators may match a given field: the first, leftmost
+    -- generator in the list will be chosen.
   , (:+) (..)
-#if __GLASGOW_HASKELL__ >= 800
   , FieldGen (..)
   , fieldGen
   , ConstrGen (..)
   , constrGen
-#endif
   , Gen1 (..)
   , Gen1_ (..)
 
@@ -145,8 +169,15 @@
   , Options ()
   , genericArbitraryWith
 
+    -- ** Setters
+  , SetOptions
+  , type (<+)
+  , setOpts
+
     -- ** Size modifiers
   , Sizing (..)
+  , SetSized
+  , SetUnsized
   , setSized
   , setUnsized
 
@@ -154,6 +185,10 @@
   , SetGens
   , setGenerators
 
+    -- ** Coherence options
+  , Coherence (..)
+  , Incoherent (..)
+
     -- ** Common options
   , SizedOpts
   , sizedOpts
@@ -162,6 +197,13 @@
   , UnsizedOpts
   , unsizedOpts
 
+    -- *** Advanced options
+    -- | See 'Coherence'
+  , CohUnsizedOpts
+  , cohUnsizedOpts
+  , CohSizedOpts
+  , cohSizedOpts
+
     -- * Generic classes
   , GArbitrary
   , GUniformWeight
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/generic-random-1.3.0.1/test/Inspect.hs 
new/generic-random-1.4.0.0/test/Inspect.hs
--- old/generic-random-1.3.0.1/test/Inspect.hs  2019-09-17 01:31:03.000000000 
+0200
+++ new/generic-random-1.4.0.0/test/Inspect.hs  2001-09-09 03:46:40.000000000 
+0200
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -dsuppress-all #-}
 {-# LANGUAGE
     DeriveGeneric,
     TemplateHaskell
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/generic-random-1.3.0.1/test/Unit.hs 
new/generic-random-1.4.0.0/test/Unit.hs
--- old/generic-random-1.3.0.1/test/Unit.hs     2019-09-06 23:48:40.000000000 
+0200
+++ new/generic-random-1.4.0.0/test/Unit.hs     2001-09-09 03:46:40.000000000 
+0200
@@ -1,5 +1,4 @@
 {-# LANGUAGE
-    CPP,
     DataKinds,
     DeriveGeneric,
     FlexibleContexts,
@@ -17,6 +16,21 @@
 
 import Generic.Random
 
+-- Binary trees
+data B = BL | BN B B
+  deriving (Eq, Ord, Show, Generic)
+
+size :: B -> Int
+size (BN l r) = 1 + size l + size r
+size BL = 0
+
+instance Arbitrary B where
+  arbitrary = genericArbitrary ((9 :: W "BL") % (3 :: W "BN") % ())
+
+instance NFData B
+
+
+-- Messing with base cases
 newtype T a = W a deriving (Generic, Show)
 
 instance (Arbitrary a, BaseCase (T a)) => Arbitrary (T a) where
@@ -24,6 +38,8 @@
 
 instance NFData a => NFData (T a)
 
+
+-- Rose tree for testing the custom list generator that's inserted by default.
 data NTree = Leaf | Node [NTree] deriving (Generic, Show)
 
 instance Arbitrary NTree where
@@ -40,24 +56,21 @@
     Just _ -> return ()
     Nothing -> fail $ name ++ ": did not finish on time"
 
-#if __GLASGOW_HASKELL__ >= 800
 -- Tests for ConstrGen
 
 data Tree2 = Leaf2 Int | Node2 Tree2 Tree2 deriving (Generic, Show)
 
 instance Arbitrary Tree2 where
-  arbitrary = genericArbitraryUG ((ConstrGen (Leaf2 <$> arbitrary) :: 
ConstrGen "Node2" 1 Tree2))
+  arbitrary = genericArbitraryUG (ConstrGen (Leaf2 <$> arbitrary) :: ConstrGen 
"Node2" 1 Tree2)
 
 isLeftBiased :: Tree2 -> Bool
 isLeftBiased (Leaf2 _) = True
 isLeftBiased (Node2 t (Leaf2 _)) = isLeftBiased t
 isLeftBiased _ = False
-#endif
 
 main :: IO ()
 main = do
+  eval "B" (arbitrary :: Gen B)
   eval "T" (arbitrary :: Gen (T (T Int)))
   eval "NTree" (arbitrary :: Gen NTree)
-#if __GLASGOW_HASKELL__ >= 800
   quickCheck . whenFail (putStrLn "Tree2") $ isLeftBiased
-#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/generic-random-1.3.0.1/test/coherence.hs 
new/generic-random-1.4.0.0/test/coherence.hs
--- old/generic-random-1.3.0.1/test/coherence.hs        1970-01-01 
01:00:00.000000000 +0100
+++ new/generic-random-1.4.0.0/test/coherence.hs        2001-09-09 
03:46:40.000000000 +0200
@@ -0,0 +1,126 @@
+{-# OPTIONS_GHC -fdefer-type-errors -Wno-deferred-type-errors #-}
+{-# LANGUAGE
+    BangPatterns,
+    DataKinds,
+    DeriveGeneric,
+    ScopedTypeVariables,
+    TypeOperators,
+    RebindableSyntax,
+    TypeApplications #-}
+
+import Control.Monad (replicateM)
+import Control.Exception
+import System.Exit (exitFailure)
+import Data.Foldable (find, traverse_)
+import Data.Maybe (catMaybes)
+
+import GHC.Generics ( Generic )
+import Test.QuickCheck (Arbitrary (..), Gen, sample, generate)
+import Prelude
+
+import Generic.Random
+
+-- @T0@, @T1@: Override the @Int@ generator in the presence of a type 
parameter @a@.
+
+-- Counterexample that's not supposed to type check.
+-- Use BangPatterns so we can force it with just seq.
+data T0 a = N0 !a !Int
+  deriving (Generic, Show)
+
+instance Arbitrary a => Arbitrary (T0 a) where
+  arbitrary = genericArbitraryWith
+      (setGenerators customGens cohSizedOpts)
+      uniform
+    where
+      customGens :: Gen Int
+      customGens = pure 33
+
+
+-- This one works.
+data T1 a = N1 a Int
+  deriving (Generic, Show)
+
+instance Arbitrary a => Arbitrary (T1 a) where
+  arbitrary = genericArbitraryWith
+      (setGenerators customGens cohSizedOpts)
+      uniform
+    where
+      customGens :: Incoherent (Gen a) :+ Gen Int
+      customGens = Incoherent arbitrary :+ pure 33
+
+check1 :: T1 a -> Bool
+check1 (N1 _ n) = n == 33
+
+
+-- A bigger example to cover the remaining generator types.
+data T2 a = N2
+  { f2a :: a
+  , f2b :: Int
+  , f2c :: [Int]
+  , f2d :: Maybe Int
+  , f2e :: Int
+  , f2g :: Int
+  , f2h :: [a]
+  } deriving (Show, Generic)
+
+instance Arbitrary a => Arbitrary (T2 a) where
+  arbitrary = genericArbitraryWith
+      (setGenerators customGens cohSizedOpts)
+      uniform
+    where
+      -- Hack to allow annotating each generator in the list while avoiding 
parentheses
+      (>>) = (:+)
+      customGens = do
+        Incoherent arbitrary :: Incoherent (Gen a)
+        Incoherent (FieldGen ((: []) <$> arbitrary))
+                             :: Incoherent (FieldGen "f2h" [a])
+        Gen1_ (pure Nothing) :: Gen1_ Maybe
+        Gen1 (fmap (\x -> [x, x])) :: Gen1 []
+        ConstrGen (pure 88)  :: ConstrGen "N2" 4 Int
+        FieldGen  (pure 77)  :: FieldGen "f2g" Int
+        pure 33              :: Gen Int
+
+check2 :: T2 a -> Bool
+check2 t =
+     f2b t == 33
+  && length (f2c t) == 2
+  && f2d t == Nothing
+  && f2e t == 88
+  && f2g t == 77
+  && length (f2h t) == 1
+
+
+type Error = String
+
+expectTypeError :: IO a -> IO (Maybe Error)
+expectTypeError gen = do
+  r <- try (gen >>= evaluate)
+  case r of
+    Left (e :: TypeError) -> pure Nothing  -- success
+    Right _ -> (pure . Just) "Unexpected evaluation (expected a type error)"
+
+
+sample_ :: Show a => (a -> Bool) -> Gen a -> IO (Maybe Error)
+sample_ check g = do
+  xs <- generate (replicateM 100 g)
+  case find (not . check) xs of
+    Nothing -> pure Nothing
+    Just x -> (pure . Just) ("Invalid value: " ++ show x)
+
+
+collectErrors :: [IO (Maybe Error)] -> IO ()
+collectErrors xs = do
+  es <- sequence xs
+  case catMaybes es of
+    [] -> pure ()
+    es@(_ : _) -> do
+      putStrLn "Test failed. Errors:"
+      traverse_ putStrLn es
+      exitFailure
+
+main :: IO ()
+main = collectErrors
+  [ expectTypeError (generate (arbitrary :: Gen (T0 ())))
+  , sample_ check1 (arbitrary :: Gen (T1 ()))
+  , sample_ check2 (arbitrary :: Gen (T2 ()))
+  ]

Reply via email to