Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.
My application depends on a couple libraries where the run off of IO, rather than a more generic m.
The code is littered with runFinal @IO . embedToFinal @IO . otherInterpreters, etc.
In order to circumvent this, I thought I could simple pass in some sort of "hoisting" function as a parameter.
runFinal @IO . embedToFinal @IO . otherInterpreters
foo :: Members [Embed IO, Async] r => (forall m a. m a -> IO a) -> Sem r a -> IO a
foo hoist sem = hoist sem
The above compiles, but the problem is passing in the "hoisting" function.
main :: IO ()
main = do
let hoist = runFinal @IO . embedToFinal @IO . asyncToIO
foo hoist undefined
The compiler complains when passing hoist to the function foo due to the type variable r being ambiguous.
Is there a way to "lift" the Sem effect to m to satisfy this constraint? Or perhaps a better way of doing what I'm trying to achieve?
the usual way to achieve this would be to use interpretFinal or withWeavingToFinal. those provide lifting combinators
I'll look into how to use those. Thanks for pointing this out!
Sorry, do you mind showing an example actually? I'm not good at reading polysemy's type signatures at all :sweat:
sure :smile: it depends heavily on what kind of combinators your IO library provides. if it's just a simple case of calling a function that expects an IO as its argument, it could look like this:
Member (Final IO) r =>
InterpreterFor Race r
interpretFinal @IO \case
Race.Race left right ->
fmap (fmap biseqEither) . Async.race <$> runS left <*> runS right
(ignore the biseqEither)
here race is IO a -> IO b -> IO (Either a b). interpretFinal expects the result of the handler to be Sem '[Strategy] x, and the runS combinator turns a Sem r x into a Sem '[Strategy] (IO (f x)).
from there you just have to make the types align (which isn't trivial either :wink: )
IO a -> IO b -> IO (Either a b)
Sem '[Strategy] x
Sem r x
Sem '[Strategy] (IO (f x))
withWeavingToFinal is a bit more low-level, and it can be used without interpreting an effect
(also possible with withStrategicToFinal)
I see, thanks a lot for the explanation! I appreciate it
if you'll still get stuck you can post some code and we'll figure it out :smile:
Going to slowly try and break down your explanation so I can fully understand that first.
If I'm still stuck after that, I'll let you know. I really do appreciate the help, thank you :grinning:
Edit: I understand the example a lot more now :grinning:
did you have success using it?