@@ -1,6 +1,7 @@
3−Generic implementation of the 'arbitrary' method. Example usage:
3+This module is a generic implementation of the 'arbitrary' method. Example
6data Foo = Foo
7data Foo = Foo
@@ -74,8 +75,52 @@ data R2 = R2 R1
76This code will compile and the @arbitrary@ generated will always hand. Yes,
77This code will compile and the @arbitrary@ generated will always hand. Yes,
77−there is a problem with mutually recursive types
78+there is a problem with mutually recursive types.
80+Now lets see an example of datatype with parameters
84+ deriving (Eq, Ord, Show)
85+ deriving anyclass NFData
88+instance (Arbitrary a) => Arbitrary (A a) where
89+ arbitrary = genericArbitrary
90+ shrink = genericShrink
93+It should work from first glance, but on compilation it will throw an error:
96+ • Could not deduce (Test.QuickCheck.Arbitrary.Generic.GArbitrary
99+ ('GHC.Generics.MetaData "A" "ParametersTest" "main" 'False)
101+ ('GHC.Generics.MetaCons "A" 'GHC.Generics.PrefixI 'False)
103+ ('GHC.Generics.MetaSel
105+ 'GHC.Generics.NoSourceUnpackedness
106+ 'GHC.Generics.NoSourceStrictness
107+ 'GHC.Generics.DecidedLazy)
108+ (GHC.Generics.Rec0 a))))
109+ (TypesDiffer (A a) a))
110+ arising from a use of ‘genericArbitrary’
113+Here the @TypesDiffer@ is a type familty dealing with recursive types and
114+helping us to eliminate inproper instances. To convince the compiller, that the
115+@a@ parameter is not an @A a@ we must fix the instance with additional constraint
118+instance (Arg (A a) a, Arbitrary a) => Arbitrary (A a) where
119+ arbitrary = genericArbitrary
120+ shrink = genericShrink
123+Now everything compiles.
@@ -85,10 +130,18 @@ module Test.QuickCheck.Arbitrary.Generic
85 , GenericArbitrary(..)
130 , GenericArbitrary(..)
88 , genericArbitrary
138 , genericArbitrary
89 , genericShrink
139 , genericShrink
92import Control.Applicative
145import Control.Applicative
93import Data.Coerce (coerce)
146import Data.Coerce (coerce)
94import Data.Proxy
147import Data.Proxy
@@ -99,6 +152,8 @@ import Test.QuickCheck as QC
99#if MIN_VERSION_QuickCheck(2, 14, 0)
152#if MIN_VERSION_QuickCheck(2, 14, 0)
100import Test.QuickCheck.Arbitrary (GSubterms, RecursivelyShrink)
153import Test.QuickCheck.Arbitrary (GSubterms, RecursivelyShrink)
102-- | Newtype for @DerivingVia@
157-- | Newtype for @DerivingVia@
103newtype GenericArbitrary a = GenericArbitrary { unGenericArbitrary :: a }
158newtype GenericArbitrary a = GenericArbitrary { unGenericArbitrary :: a }
104 deriving (Show, Eq)
159 deriving (Show, Eq)
@@ -113,12 +168,12 @@ instance
113 shrink = coerce (genericShrink :: a -> [a])
168 shrink = coerce (genericShrink :: a -> [a])
171+type Arg self field = (TypesDiffer self field ~ 'True)
116type family TypesDiffer a b where
173type family TypesDiffer a b where
117 TypesDiffer a a = 'False
174 TypesDiffer a a = 'False
118 TypesDiffer a b = 'True
175 TypesDiffer a b = 'True
120−type Arg self field = (TypesDiffer self field ~ 'True)
122type family AllFieldsFinal self (a :: * -> *) :: Bool where
177type family AllFieldsFinal self (a :: * -> *) :: Bool where
123 AllFieldsFinal self U1 = 'True
178 AllFieldsFinal self U1 = 'True
124 AllFieldsFinal self (a :*: b) = AllFieldsFinal self a && AllFieldsFinal self b
179 AllFieldsFinal self (a :*: b) = AllFieldsFinal self a && AllFieldsFinal self b