I've been trying to write an implementation of the function:
foo :: Monad m => ConduitM i o (forall s. STT s m) r -> ConduitM i o m r
But I've been failing at every turn with the error:
Couldn't match type because variable `s` would escape its scope.
I'm now suspicious that implementing this function is impossible.
threadSTT :: Monad m
=> (forall a. (forall s. STT s m a) -> m a)
-> ConduitM i o (forall s. STT s m) r
-> ConduitM i o m r
threadSTT runM (ConduitM c0) =
ConduitM $ \rest ->
let go (Done r) = rest r
go (PipeM mp) = PipeM $ do
r <- runM mp -- ERROR
return $ go r
go (Leftover p i) = Leftover (go p) i
go (NeedInput x y) = NeedInput (go . x) (go . y)
go (HaveOutput p f o) = HaveOutput (go p) (runM f) o -- ERROR
in go (c0 Done)
foo :: Monad m => ConduitM i o (forall s. STT s m) r -> ConduitM i o m r
foo = threadSTT STT.runST
Can anyone speak to this? I'd really love it to work, but if I can't then I need abandon use of Data.Array.ST
for writing my conduits.
It seems that you have reinvented the MFunctor
instance of ConduitM
. You may check the source code.
By the author of conduit package, monad hoist in this style gives surprising results when you try to unwrap a monad with side effect. In you case runST
will be called multiple times so the state is thrown every time the conduit produces an item.
You'd better lift every other conduit on the line from Conduit i o m r
to Conduit i o (STT s m) r
and call runST
on the result. It's as easy as transPipe lift
.