{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} module Test.Monad.State.Mutants where import Control.Monad.State import Data.Functor.Identity import Test.QuickCheck.HigherOrder (Equation(..)) import Test.Mutants bad_get_put_get :: forall m s. MonadState s m => s -> Equation (m s) bad_get_put_get s = (put s >> get) :=: (get >>= \s' -> put s >> return @m s') bad_put_put :: forall m s. MonadState s m => s -> s -> Equation (m ()) bad_put_put s1 s2 = (put s1 >> put s2) :=: put @_ @m s1 -- * 'StateT' mutant -- Can't get 'get' wrong. -- Only one way to get 'put' wrong. -- -- Parametricity! data PutDoesNothing -- | Fails: -- -- > 'put_get' -- -- Passes (wrongly): -- -- > 'bad_get_put_get' -- > 'bad_put_put' type MutantStateT s = Mutant PutDoesNothing (StateT s) type MutantState s = MutantStateT s Identity instance {-# OVERLAPPING #-} Monad m => MonadState s (MutantStateT s m) where get = Mutant get put _s = Mutant $ StateT $ \s -> return ((), s) -- "oops"