2

我一直在尝试编写该函数的实现:

foo :: Monad m => ConduitM i o (forall s. STT s m) r -> ConduitM i o m r

但是我每次都因错误而失败:

Couldn't match type because variable `s` would escape its scope.

我现在怀疑实现这个功能是不可能的。

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

任何人都可以谈论这个吗?我真的很喜欢它的工作,但如果我不能,那么我需要放弃使用Data.Array.ST来编写我的管道。

4

1 回答 1

2

您似乎重新发明MFunctorConduitM. 您可以查看源代码

通过导管包的作者,当您尝试打开具有副作用的 monad 时,这种风格的 monad 提升器会产生令人惊讶的结果。在您的情况下runST,将被多次调用,因此每次管道产生项目时都会抛出状态。

您最好将线路上的所有其他管道从Conduit i o m rto 提升Conduit i o (STT s m) r并调用runST结果。这很容易transPipe lift

于 2016-02-07T08:41:58.640 回答