How to hoist Conduit of STT

151 views Asked by At

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.

1

There are 1 answers

0
zakyggaps On BEST ANSWER

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.