@@ -1,6 +1,7 @@
1−{- |
1+{-|
22
3−Generic implementation of the 'arbitrary' method. Example usage:
3+This module is a generic implementation of the 'arbitrary' method. Example
4+usage:
45
56@
67data Foo = Foo
@@ -74,8 +75,52 @@ data R2 = R2 R1
7475@
7576
7677This 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.
7879
80+Now lets see an example of datatype with parameters
81+
82+@
83+data A a = A a
84+ deriving (Eq, Ord, Show)
85+ deriving anyclass NFData
86+ deriving (Generic)
87+
88+instance (Arbitrary a) => Arbitrary (A a) where
89+ arbitrary = genericArbitrary
90+ shrink = genericShrink
91+@
92+
93+It should work from first glance, but on compilation it will throw an error:
94+
95+@
96+ • Could not deduce (Test.QuickCheck.Arbitrary.Generic.GArbitrary
97+ (A a)
98+ (GHC.Generics.D1
99+ ('GHC.Generics.MetaData "A" "ParametersTest" "main" 'False)
100+ (GHC.Generics.C1
101+ ('GHC.Generics.MetaCons "A" 'GHC.Generics.PrefixI 'False)
102+ (GHC.Generics.S1
103+ ('GHC.Generics.MetaSel
104+ 'Nothing
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’
111+@
112+
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
116+
117+@
118+instance (Arg (A a) a, Arbitrary a) => Arbitrary (A a) where
119+ arbitrary = genericArbitrary
120+ shrink = genericShrink
121+@
122+
123+Now everything compiles.
79124
80125-}
81126
@@ -85,10 +130,18 @@ module Test.QuickCheck.Arbitrary.Generic
85130 , GenericArbitrary(..)
86131#endif
87132 , Arg
133+ , TypesDiffer
134+ , AllFieldsFinal
135+ , Finite
136+ , ArgumentsCount
137+ , SumLen
88138 , genericArbitrary
89139 , genericShrink
90140 ) where
91141
142+
143+
144+
92145import Control.Applicative
93146import Data.Coerce (coerce)
94147import Data.Proxy
@@ -99,6 +152,8 @@ import Test.QuickCheck as QC
99152#if MIN_VERSION_QuickCheck(2, 14, 0)
100153import Test.QuickCheck.Arbitrary (GSubterms, RecursivelyShrink)
101154
155+
156+
102157-- | Newtype for @DerivingVia@
103158newtype GenericArbitrary a = GenericArbitrary { unGenericArbitrary :: a }
104159 deriving (Show, Eq)
@@ -113,12 +168,12 @@ instance
113168 shrink = coerce (genericShrink :: a -> [a])
114169#endif
115170
171+type Arg self field = (TypesDiffer self field ~ 'True)
172+
116173type family TypesDiffer a b where
117174 TypesDiffer a a = 'False
118175 TypesDiffer a b = 'True
119176
120−type Arg self field = (TypesDiffer self field ~ 'True)
121−
122177type family AllFieldsFinal self (a :: * -> *) :: Bool where
123178 AllFieldsFinal self U1 = 'True
124179 AllFieldsFinal self (a :*: b) = AllFieldsFinal self a && AllFieldsFinal self b