Why is there an unexpected “expected type” of () in this conduit composition (fusion)?

≡放荡痞女 提交于 2019-12-24 11:18:20

问题


I have the following conduit components that are being fused together:

awaitVals () :: ConduitT (Element mono) (Element mono) m ()
intermTmp :: forall o. (Element mono -> Bool) -> ConduitT (Element mono) o m ([Element mono])

The fusion occurs like: awaitVals () .| intermTmp curPred.

According to the fuse function (.|), I think the types should be OK here. Fuse is:

(.|) :: Monad m
     => ConduitT a b m ()
     -> ConduitT b c m r
     -> ConduitT a c m r

Here's the entire function definition:

takeWhileGrouped :: forall m mono. (Monad m, MonoFoldable mono) =>
  ([Element mono -> Bool])
  -> ConduitT (Element mono) [Element mono] m ()
takeWhileGrouped preds = go preds
  where
    go (curPred:nextPreds) = yieldM (goIter curPred) >> go nextPreds
    go [] = yield []
    intermTmp :: forall o. (Element mono -> Bool) -> ConduitT (Element mono) o m ([Element mono])
    intermTmp curPred = CC.takeWhile curPred .| sinkList
    goIter :: (Element mono -> Bool) -> m ([Element mono])
    goIter curPred =
      (awaitVals () :: ConduitT (Element mono) (Element mono) m ())
        .| (intermTmp curPred) & runConduit

awaitVals :: forall a m. Monad m => () -> ConduitT a a m ()
awaitVals _ = do
  nextValMay <- await
  case nextValMay of
    Just val -> do
      yield val
      awaitVals ()
    Nothing -> pure ()

And here is the error:

    • Couldn't match type ‘Element mono’ with ‘()’
      Expected type: ConduitM () () m ()
        Actual type: ConduitT (Element mono) (Element mono) m ()
    • In the first argument of ‘(.|)’, namely
        ‘(awaitVals () :: ConduitT (Element mono) (Element mono) m ())’
      In the first argument of ‘(&)’, namely
        ‘(awaitVals () :: ConduitT (Element mono) (Element mono) m ())
           .| (intermTmp curPred)’
      In the expression:
        (awaitVals () :: ConduitT (Element mono) (Element mono) m ())
          .| (intermTmp curPred)
          & runConduit
    • Relevant bindings include
        curPred :: Element mono -> Bool
          (bound at src/FDS/Data/Conduits.hs:151:12)
        goIter :: (Element mono -> Bool) -> m [Element mono]
          (bound at src/FDS/Data/Conduits.hs:151:5)
        intermTmp :: forall o.
                     (Element mono -> Bool)
                     -> ConduitT (Element mono) o m [Element mono]
          (bound at src/FDS/Data/Conduits.hs:149:5)
        preds :: [Element mono -> Bool]
          (bound at src/FDS/Data/Conduits.hs:144:18)
        takeWhileGrouped :: [Element mono -> Bool]
                            -> ConduitT (Element mono) [Element mono] m ()
          (bound at src/FDS/Data/Conduits.hs:144:1)
    |
151 |     goIter curPred = (awaitVals () :: ConduitT (Element mono) (Element mono) m ()) .| (intermTmp curPred) & runConduit
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I don't understand why the expected type disagrees with the actual type. Here's a more general question that I haven't totally wrapped up, but it does have a working solution near the end (but it doesn't use fuse to compose conduits at the outermost level): How to implement a takeWhile-like function using Conduit combinators? I should probably wait to look at this after having slept a reasonable amount, but I was very curious about this...


回答1:


The reason is that runConduit requires () to be in the input type of the conduit component it is passed. But that is clearly not what we have here: we need a source for that, and we just don't have one in this context. Then we need to implement the function without using runConduit, so we can no longer construct intermediary conduits. See How to implement a takeWhile-like function using Conduit combinators? for an implementation that works.

Note: I came to this conclusion after playing out with the following conduits that made it a bit easier to see what was happening with types and variation in composition. The commented out examples have trouble compiling.

testCondComposedSink :: forall i o m. Monad m => ConduitT i o m [i]
testCondComposedSink = awaitVals () .| sinkList

testCondComposedTakeW :: forall i m. Monad m => ConduitT i i m ()
testCondComposedTakeW = awaitVals () .| CC.takeWhile (\_ -> True)

testCondComposedAll :: forall i o m. Monad m => ConduitT i o m [i]
testCondComposedAll = awaitVals () .| CC.takeWhile (\_ -> True) .| sinkList

takeWhileSinkList :: forall i o m. Monad m => (i -> Bool) -> ConduitT i o m [i]
takeWhileSinkList predicate = CC.takeWhile predicate .| sinkList

testCondComposedAll2 :: forall i o m. Monad m => ConduitT i o m [i]
testCondComposedAll2 = awaitVals () .| takeWhileSinkList (\_ -> True)

-- testCondComposedAll2Run ::  forall i m. Monad m => m [i]
-- testCondComposedAll2Run = testCondComposedAll2 & runConduit

-- takeWhileSinkList2 :: forall i m. Monad m => (i -> Bool) -> ConduitT () Void m [i]
-- takeWhileSinkList2 predicate = CC.takeWhile predicate .| sinkList

-- testCondComposedAll3 :: forall i o m. Monad m => ConduitT () o m [i]
-- testCondComposedAll3 = awaitVals () .| takeWhileSinkList2 (\_ -> True)

-- testCondComposedAll3Run ::  forall i m. Monad m => m [i]
-- testCondComposedAll3Run = testCondComposedAll3 & runConduit

-- testCondDownsteram :: forall i o r m. Monad m => () -> ConduitT i o m r
-- testCondDownsteram = undefined


来源:https://stackoverflow.com/questions/58107971/why-is-there-an-unexpected-expected-type-of-in-this-conduit-composition-fu

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!