{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-}
module EquivSpec where
import Polysemy
import Polysemy.Check
import Test.Hspec
import Test.QuickCheck
import Test.Hspec.QuickCheck
import Polysemy.State
import Data.IORef (newIORef)
import Unsafe.Coerce (unsafeCoerce)
spec :: Spec
spec = do
prop "Pure state is equivalent to IO state" $ do
s0 <- arbitrary
pure $
prepropEquivalent @'[State Int] @Int
(runPureState s0)
(runIOState s0)
$ ((do
SomeAction e1 <- arbitraryAction @(State Int) @r
SomeAction e2 <- arbitraryAction @(State Int) @r
SomeAction e3 <- arbitraryAction @(State Int) @r
-- TODO(sandy): e3 has an existential type! GHC doesn't care, but
-- AFAIK, thereis no syntax to return this type, since it doesn't
-- exist when we bind 'a' below.
pure $ send e1 >> send e2 >> unsafeCoerce (send e3)
) :: forall r a. Member (State Int) r => Gen (Sem r a))
runPureState :: Int -> Sem '[State Int] a -> IO a
runPureState s = pure . run . evalState s
runIOState :: Int -> Sem '[State Int, Embed IO] a -> IO (a)
runIOState s sem = do
ref <- newIORef s
runM . runStateIORef ref $ sem