Почему в этой композиции каналов (слияние) присутствует неожиданный ожидаемый тип ()?

У меня есть следующие компоненты трубопровода, которые сплавляются вместе:

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

Слияние происходит так: awaitVals () .| intermTmp curPred.

Согласно функции предохранителя (.|), я думаю, что типы здесь должны быть в порядке. Предохранитель:

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

Вот полное определение функции:

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 ()

И вот ошибка:

    • 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
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Я не понимаю, почему ожидаемый тип не совпадает с фактическим типом. Вот более общий вопрос, который я не полностью рассмотрел, но у него есть рабочее решение ближе к концу (но он не использует предохранитель для создания каналов на самом внешнем уровне): Как реализовать функцию, подобную takeWhile, с помощью комбинаторов Conduit? Вероятно, мне следует подождать, чтобы посмотрите на это после того, как выспитесь, но мне было очень любопытно об этом ...


person bbarker    schedule 26.09.2019    source источник
comment
Я только что заметил, что в сообщении есть ConduitM, но, по-видимому, type ConduitM = ConduitT, так что проблема не в этом.   -  person bbarker    schedule 26.09.2019
comment
Я начинаю понимать, что проблема связана с runConduit (и всеми его вариантами), ожидающими () во входной позиции, и, соответственно, у меня нет источника, который бы имел единицу во входной позиции, как сейчас написано .... хм   -  person bbarker    schedule 26.09.2019


Ответы (1)


Причина в том, что runConduit требует, чтобы () был во входном типе компонента канала, который он передает. Но это явно не то, что у нас здесь есть: для этого нам нужен источник, а у нас его просто нет в данном контексте. Затем нам нужно реализовать функцию без использования runConduit, чтобы мы больше не могли создавать промежуточные каналы. См. Как реализовать функцию, подобную takeWhile, с помощью комбинаторов Conduit. ? для реализации, которая работает.

Примечание. Я пришел к такому выводу после того, как поиграл со следующими проводниками, которые немного упростили понимание того, что происходит с типами и вариациями в композиции. Закомментированные примеры имеют проблемы с компиляцией.

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
person bbarker    schedule 26.09.2019