3[](https://github.com/typeable/generic-arbitrary/actions/workflows/haskell-ci.yml)
7Package for deriving `Arbitrary` via `Generic`.
10import GHC.Generics (Generic)
12import Test.QuickCheck.Arbitrary.Generic
18 deriving (Eq, Show, Generic)
19 deriving Arbitrary via (GenericArbitrary Expr)
22Older versions of this package had a problem with hanging `arbitrary`
23method. Since `1.0.0` this problem almost solved.
25For `QuickCheck` older than `2.14.0` the `GenericArbitrary` is not available, so
26you will need to write instances more verbosely
33 deriving (Eq, Show, Generic)
35instance Arbitrary Expr where
36 arbitrary = genericArbitrary
37 shrink = genericShrink
40Which is generally the same.
42# Infinite terms problem
44The `generic-arbitrary` can partially handle the problem with recursive
45types. Assume the type `R`
55instance Arbitrary R where
56 arbitrary = genericArbitrary
57 shrink = genericShrink
60If you try to compile this you will get a type level error
62> • R refers to itself in all constructors
64Which means that there is no finite term for `R` because it is recursive in all
65it's constructors. But, if you correct the definition of `R` like this.
72Then it will compile. And the `arbitrary` generated will not hang forever,
73because it respects the `size` parameter.
77There is a limitation of recursion detection:
81 deriving (Eq, Ord, Show, Generic)
82 deriving anyclass NFData
83 deriving Arbitrary via (GenericArbitrary R1)
86 deriving (Eq, Ord, Show, Generic)
87 deriving anyclass NFData
88 deriving Arbitrary via (GenericArbitrary R2)
91This code will compile and the `arbitrary` generated will always hang. Yes,
92there is a problem with mutually recursive types.
96Now let's see an example of datatype with parameters
100 deriving (Eq, Ord, Show)
101 deriving anyclass NFData
104instance (Arbitrary a) => Arbitrary (A a) where
105 arbitrary = genericArbitrary
106 shrink = genericShrink
109It should work from first glance, but when compile it will throw an error:
112• Could not deduce (Test.QuickCheck.Arbitrary.Generic.GArbitrary
115 ('GHC.Generics.MetaData "A" "ParametersTest" "main" 'False)
117 ('GHC.Generics.MetaCons "A" 'GHC.Generics.PrefixI 'False)
119 ('GHC.Generics.MetaSel
121 'GHC.Generics.NoSourceUnpackedness
122 'GHC.Generics.NoSourceStrictness
123 'GHC.Generics.DecidedLazy)
124 (GHC.Generics.Rec0 a))))
125 (TypesDiffer (A a) a))
126 arising from a use of ‘genericArbitrary’
129Here the `TypesDiffer` is a type familty dealing with recursive types and
130helping us to eliminate inproper instances. To convince the compiller, that the
131`a` parameter is not an `A a` we must fix the instance with additional
132constraint `Arg (A a) a`
135instance (Arg (A a) a, Arbitrary a) => Arbitrary (A a) where
136 arbitrary = genericArbitrary
137 shrink = genericShrink
140Now everything compiles and works as expected.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list