Static vs dynamic - are they really that different? #169
-
Hello,
As far as I can see though, a dynamic effect can be implemented via a static effect by just parameterising the static interpreter with a record of functions. So where the run time behaviour of a dynamic effect can be changed by switching the interpreter, the behaviour of the static effect can be changed by switching the record of functions argument. Is there any fundamental differences (user or runtime) in these approaches? ExampleStatic{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
module EffPlay.SpeakIOInterpreterStatic where
import qualified Data.Text.IO as T
import Effectful (Dispatch (Static), DispatchOf, Eff, Effect, IOE, runEff, (:>))
import Effectful.Dispatch.Static (SideEffects (WithSideEffects), StaticRep, evalStaticRep, getStaticRep, unsafeEff_)
-- Effect
data Speak :: Effect
data Speaker = Speaker
{ hello :: Text -> IO ()
, goodbye :: Text -> IO ()
}
newtype instance StaticRep Speak = Speak Speaker
type instance DispatchOf Speak = Static WithSideEffects
hello :: (Speak :> es) => Text -> Eff es ()
hello name = do
Speak s <- getStaticRep
unsafeEff_ $ s.hello name
goodbye :: (Speak :> es) => Text -> Eff es ()
goodbye name = do
Speak s <- getStaticRep
unsafeEff_ $ s.goodbye name
-- Interpreter
runSpeaker :: (HasCallStack, IOE :> es) => Speaker -> Eff (Speak : es) a -> Eff es a
runSpeaker speaker = evalStaticRep (Speak speaker)
-- Dynamic Params
staticImp :: Speaker
staticImp =
Speaker
{ hello = \name -> T.putStrLn $ "Hello (static) " <> name
, goodbye = \name -> T.putStrLn $ "Goodbye (static) " <> name
}
staticImpCasual :: Speaker
staticImpCasual =
Speaker
{ hello = \name -> T.putStrLn $ "hi (static) " <> name
, goodbye = \name -> T.putStrLn $ "bye (static) " <> name
}
-- Effectful Ap
speakApp :: Text -> Eff (Speak : es) ()
speakApp name = do
hello name
goodbye name
-- Implementation
-- $> exeSpeakerAppStatic
exeSpeakerAppStatic :: IO ()
exeSpeakerAppStatic = do
runEff . runSpeaker staticImp $ speakApp "John"
-- $> exeSpeakerAppStaticCasual
exeSpeakerAppStaticCasual :: IO ()
exeSpeakerAppStaticCasual = do
runEff . runSpeaker staticImpCasual $ speakApp "John" Dynamic{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
module EffPlay.SpeakIOInterpreterDynamic where
import qualified Data.Text.IO as T
import Effectful as EF (
Dispatch (Dynamic),
DispatchOf,
Eff,
Effect,
IOE,
liftIO,
runEff,
type (:>),
)
import Effectful.Dispatch.Dynamic (
HasCallStack,
interpret,
)
import Effectful.TH (makeEffect)
-- Effect
type instance DispatchOf Speak = Dynamic
data Speak :: Effect where
Hello :: Text -> Speak m ()
Goodbye :: Text -> Speak m ()
makeEffect ''Speak
-- Interpreters
runSpeak :: forall es a. (HasCallStack, IOE :> es) => Eff (Speak : es) a -> Eff es a
runSpeak =
interpret $ \_ ->
EF.liftIO . \case
Hello name -> T.putStrLn $ "Hello (dynamic) " <> name
Goodbye name -> T.putStrLn $ "Goodbye (dynamic) " <> name
runSpeakCasual :: forall es a. (HasCallStack, IOE :> es) => Eff (Speak : es) a -> Eff es a
runSpeakCasual =
interpret $ \_ ->
EF.liftIO . \case
Hello name -> T.putStrLn $ "hi (dynamic) " <> name
Goodbye name -> T.putStrLn $ "bye (dynamic) " <> name
-- Effectful Ap
speakApp :: Text -> Eff (Speak : es) ()
speakApp name = do
hello name
goodbye name
-- Implementation
-- $> exeSpeakerApp
exeSpeakerApp :: IO ()
exeSpeakerApp =
runEff . runSpeak $ speakApp "John"
-- $> exeSpeakerAppCasual
exeSpeakerAppCasual :: IO ()
exeSpeakerAppCasual =
runEff . runSpeakCasual $ speakApp "John" RunC:\Pyrethrum\src\EffPlay\SpeakIOInterpreterDynamic.hs:71:1
$> exeSpeakerApp
Hello (dynamic) John
Goodbye (dynamic) John
C:\Pyrethrum\src\EffPlay\SpeakIOInterpreterDynamic.hs:76:1
$> exeSpeakerAppCasual
hi (dynamic) John
bye (dynamic) John
C:\Pyrethrum\src\EffPlay\SpeakIOInterpreterStatic.hs:60:1
$> exeSpeakerAppStatic
Hello (static) John
Goodbye (static) John
C:\Pyrethrum\src\EffPlay\SpeakIOInterpreterStatic.hs:65:1
$> exeSpeakerAppStaticCasual
hi (static) John
bye (static) John |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Correct.
I don't know about fundamental, but with dynamic effects you can easily re-use other effects with
|
Beta Was this translation helpful? Give feedback.
Correct.
I don't know about fundamental, but with dynamic effects you can easily re-use other effects with
reinterpret
.Pretty much 🙂 See this vs this.