-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
can you use polysemy with ST-like "thread" types? #435
Comments
If your approach did work (note my use of module ST where
import Control.Monad.ST (runST, ST)
import Polysemy (Sem, Member, run, interpret)
import Polysemy.Internal (send)
import Unsafe.Coerce (unsafeCoerce)
import Data.STRef (newSTRef, STRef)
data STE s m a where
STE :: ST s a -> STE s m a
ste :: Member (STE s) r => STE s (Sem r) a -> Sem r a
ste = send
runSTE ::
forall r s a.
Sem (STE s ': r) a ->
Sem r a
runSTE = interpret $ \case
STE x -> pure $ runST $ unsafeCoerce x
whoops :: forall s. STRef s Integer
whoops = run $ runSTE @_ @s ref
ref :: forall s r. Member (STE s) r => Sem r (STRef s Integer)
ref = ste $ STE $ newSTRef 42 I'm not sure what needs to be different to fill your use case. |
This is a good analogue of what I want, thanks! Could there be another approach that works? |
I think so, because you would be able to pass your " In other words, the same problem that you get (afaik) from trying to thread the Not sure how viable this would be for |
Seems doable once you look at #!/usr/bin/env stack
-- stack repl --package polysemy --package polysemy-plugin --package STMonadTrans
{-# options_ghc -fplugin=Polysemy.Plugin #-}
{-# language TemplateHaskell, BlockArguments, RankNTypes, LambdaCase, TypeApplications, ScopedTypeVariables, TypeOperators, GADTs, DataKinds, PolyKinds, FlexibleContexts, MagicHash #-}
module PolysemyST where
import GHC.Exts (State#)
import qualified Control.Monad.ST.Trans as ST
import Control.Monad.ST.Trans.Internal (STT (..), STTRet (..))
import Data.Functor
import Polysemy
import Polysemy.Internal
import Polysemy.Internal.Union
import Unsafe.Coerce (unsafeCoerce)
import Data.Functor.Compose
import Data.STRef (STRef)
data STE s :: Effect where
NewSTRef :: a -> STE s m (STRef s a)
ReadSTRef :: STRef s a -> STE s m a
WriteSTRef :: STRef s a -> a -> STE s m ()
makeSem ''STE
runSTE :: forall r a . (forall s . Sem (STE s ': r) a) -> Sem r a
runSTE sem = ST.runSTT $ STT $ go sem where
go :: forall r a s . Sem (STE s ': r) a -> State# s -> Sem r (STTRet s a)
go (Sem sa) s = Sem \k -> let
STT f = sa \u -> case decomp u of
Left rest -> STT \s -> k $ weave
(STTRet s ())
(\(STTRet s sa) -> go sa s)
(Just . \(STTRet _ a) -> a)
rest
Right (Weaving e fs d r _) -> case e of
NewSTRef a -> r . (fs $>) <$> ST.newSTRef a
ReadSTRef ref -> r . (fs $>) <$> ST.readSTRef ref
WriteSTRef ref a -> r . (fs $>) <$> ST.writeSTRef ref a
in f s
-- Does not typecheck
-- whoops :: forall s. STRef s Integer
-- whoops = run $ runSTE ref
ref :: forall s r. Member (STE s) r => Sem r (STRef s Integer)
ref = newSTRef 42
main :: IO ()
main = print $ run $ runSTE do
r <- ref
a <- readSTRef r
writeSTRef r 43
b <- readSTRef r
pure (a, b) |
🧐 |
@TheMatten can you do that with |
eh no, there's no safe analogue of |
oh and this implementation doesn't even run in |
@tek |
@TheMatten thanks for this, I admit it took me few hours staring into this until I understood what's happening ;) Tried to do this for my case, sadly I think I'm still out of luck, as my concrete effects have also MonadIO constraint, which propagate from Right branch, but Sem does not have it. |
I have this type from GPipe library:
ContextT Handle os IO a
whereos
is this "thread" type that limits the scope of what's insideContextT
, much like withST
monadand I have a function
runContextT :: (forall os. ContextT Handle os IO x) -> IO x
I'd like to be able to use use this with polysemy so I can mix other effects inside ContexT
currently I my effects are run in IO and then I liftIO to ContextT, but I'd like it to be a bit more streamlined (and testable).
So I wanted to make ContextT be basically the last effect on my stack to be interpreted IO, I tried wrapping this with my own type and interpreting it:
and then interpreting:
I'm getting
Could not deduce: os1 ~ os
, so look's like I'm missing some RankN forall qualifier somewhere? I'm not even sure what I'm trying is possible in principle, any ideas?The text was updated successfully, but these errors were encountered: