{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} module Test.QuickCheck.HigherOrder.Internal.Constructible where import Data.Functor.Identity import qualified Data.Monoid as Monoid import Test.QuickCheck (Arbitrary(..), Function, CoArbitrary, Fun) -- * The 'Constructible' class -- | A 'Constructible' type is associated with a type of "finite descriptions" -- that can be generated, shown (e.g., as counterexamples in QuickCheck), and -- interpreted as values. -- This enhances 'Arbitrary' and 'Show' used by vanilla QuickCheck. -- -- The main motivating example is the type of functions, which can be -- finitely represented by the type @('Test.QuickCheck.HigherOrder.:->')@ -- (see also "Test.Fun"). -- -- It turns out we can define 'Constructible' for just about anything -- except 'IO' (for now...). class (Arbitrary (Repr a), Show (Repr a)) => Constructible a where -- | The observable representation of a value. type Repr a type instance Repr a = a -- | Interpret a representation as a value. fromRepr :: Repr a -> a -- * The 'Constructed' modifier -- | 'Constructible' wrapper with 'Show' and 'Arbitrary' instances -- that operate on the representation of the argument type. -- -- Deconstruct with the 'Construct' pattern. -- -- This is only useful for property combinators from vanilla QuickCheck, that -- use the original 'Testable' class instead of -- 'Test.QuickCheck.HigherOrder.Testable'' from this library. data Constructed a = Constructed (Repr a) a -- | A unidirectional pattern to deconstruct 'Constructed' values. pattern Construct :: a -> Constructed a pattern Construct a <- Constructed _ a -- | A smart constructor for constructible values. mkConstructed :: Constructible a => Repr a -> Constructed a mkConstructed r = Constructed r (fromRepr r) instance Constructible a => Arbitrary (Constructed a) where arbitrary = fmap mkConstructed arbitrary shrink (Constructed r _) = fmap mkConstructed (shrink r) instance Constructible a => Show (Constructed a) where showsPrec n (Constructed r _) = showParen (n > 10) $ showString "Constructed " . showsPrec 11 r . showString " _" -- 'Constructible' instances instance (CoArbitrary a, Function a, Show a, Constructible b) => Constructible (Fun a b) where type Repr (Fun a b) = Fun a (Repr b) fromRepr = fmap fromRepr instance Constructible a => Constructible (Identity a) where type Repr (Identity a) = Repr a fromRepr = Identity . fromRepr instance (Constructible a, Constructible b) => Constructible (a, b) where type Repr (a, b) = (Repr a, Repr b) fromRepr (a, b) = (fromRepr a, fromRepr b) instance (Constructible a, Constructible b) => Constructible (Either a b) where type Repr (Either a b) = Either (Repr a) (Repr b) fromRepr (Left a) = Left (fromRepr a) fromRepr (Right b) = Right (fromRepr b) instance Constructible a => Constructible (Maybe a) where type Repr (Maybe a) = Maybe (Repr a) fromRepr = fmap fromRepr instance Constructible a => Constructible [a] where type Repr [a] = [Repr a] fromRepr = fmap fromRepr instance Constructible Integer where fromRepr = id instance Constructible Int where fromRepr = id instance Constructible Word where fromRepr = id instance Constructible Double where fromRepr = id instance Constructible Char where fromRepr = id instance Constructible () where fromRepr = id instance Constructible Bool where fromRepr = id instance Constructible Ordering where fromRepr = id instance Constructible a => Constructible (Monoid.Sum a) where type Repr (Monoid.Sum a) = Monoid.Sum (Repr a) fromRepr = Monoid.Sum . fromRepr . Monoid.getSum