module Polysemy.State.Keyed.Law where
import Data.Constraint.Extras
import Data.GADT.Compare
import Data.GADT.Show
import Data.Some
import Data.Type.Equality
import Polysemy
import Polysemy.Law
import Polysemy.State.Keyed
prop_lawfulKeyedState ::
forall k r.
MakeLaw (KeyedState k) r =>
(forall a. Eq a => Eq (k a), GEq k, GShow k) =>
(Has Show k, Has Eq k, Has Arbitrary k, Arbitrary (Some k)) =>
InterpreterFor (KeyedState k) r -> Property
prop_lawfulKeyedState f = runLaw f law_consistency
newtype KeyValuePair k a = KeyValuePair (k a, a)
instance GEq k => GEq (KeyValuePair k) where
geq (KeyValuePair (x,_)) (KeyValuePair (y,_)) = geq x y
instance (Has Arbitrary k, Arbitrary (Some k)) => Arbitrary (Some (KeyValuePair k)) where
arbitrary =
withSomeM arbitrary $ \(k :: k a) ->
has @Arbitrary k $ Some . KeyValuePair . (k,) <$> arbitrary
instance (Has Show k, GShow k) => GShow (KeyValuePair k) where
gshowsPrec i (KeyValuePair (k, x)) s =
has @Show k $ concat ["(", gshowsPrec i k "", ", ", showsPrec i x "", ")", s]
law_consistency ::
forall k r.
MakeLaw (KeyedState k) r =>
(forall a. Eq a => Eq (k a), GEq k, GShow k) =>
(Has Show k, Has Eq k, Has Arbitrary k, Arbitrary (Some k)) =>
Law (KeyedState k) r
law_consistency =
mkLaw @_ @_ @_ @(_ -> _ -> Sem _ (Some (KeyValuePair k)))
"uncurry putAt %1 *> getAt %2"
(\(Some (KeyValuePair (k, x))) (Some k') ->
putAt k x *> (Some . KeyValuePair . (k',) <$> getAt k'))
"if fst %1 == %2 then pure (snd %1) else getAt %2"
(\(Some (KeyValuePair (k, x))) (Some k') ->
case geq k k' of
Just Refl | has @Eq k $ k == k' -> pure $ Some $ KeyValuePair (k, x)
_ -> Some . KeyValuePair . (k',) <$> getAt k')