默认情况下,管道是基于拉取的。这是由于>->
运算符由+>>
实现的,bind
是其拉取类别的有点producer >-> consumer
运算符。我的理解是,这意味着如果你有像pipes
这样的代码,将首先调用消费者的身体,然后一旦等待数据,就会调用生产者。
我在(reflect .)
文档here中看到,您可以使用Pipes.Core
中的代码producer >-> consumer
将基于拉的管道转换为基于推送的管道。这意味着(纠正我,如果我错了)在上面的代码>->
中,生产者先运行,产生一个值,然后消费者试图消费。这似乎非常有用,我想知道如何做到这一点。
我在讨论here中也看到,stdin :: Producer String IO r
stdin = forever $ do
lift $ putStrLn "stdin"
str <- lift getLine
yield str
countLetters :: Consumer String IO r
countLetters = forever $ do
lift $ putStrLn "countLetters"
str <- await
lift . putStrLn . show . length $ str
-- this works in pull mode
runEffect (stdin >-> countLetters)
-- equivalent to above, works
runEffect ((\() -> stdin) +>> countLetters)
-- push based operator, doesn't do what I hoped
runEffect (stdin >>~ (\_ -> countLetters))
-- does not compile
runEffect (countLetters >>~ (\() -> stdin))
没有基于推送的对应物,因为很容易转换任何管道(我假设有反射?),但我不能真的想知道如何做或找到任何例子。
以下是我尝试的一些代码:
setMouseTracking(true);
答案 0 :(得分:2)
-- push based operator, doesn't do what I hoped runEffect (stdin >>~ (\_ -> countLetters))
我在这里收集的问题是,当生产者按预期运行时,第一个生成的值被删除。比较...
GHCi> runEffect (stdin >-> countLetters)
countLetters
stdin
foo
3
countLetters
stdin
glub
4
countLetters
stdin
... with:
GHCi> runEffect (stdin >>~ (\_ -> countLetters))
stdin
foo
countLetters
stdin
glub
4
countLetters
stdin
Gabriel Gonzalez&#39;详细讨论了这个问题。回答this question。它归结为你给(>>~)
的函数的参数是如何驱动&#34;驾驶&#34;在基于推送的流程中输入,所以如果你const
它输出,你最终会丢弃第一个输入。解决方案是相应地重塑countLetters
:
countLettersPush :: String -> Consumer String IO r
countLettersPush str = do
lift $ putStrLn "countLetters"
lift . putStrLn . show . length $ str
str' <- await
countLettersPush str'
GHCi> runEffect (stdin >>~ countLettersPush)
stdin
foo
countLetters
3
stdin
glub
countLetters
4
stdin
我在讨论here中也看到,
>->
没有基于推送的对应物,因为很容易转换任何管道(我假设有反射?)
我不完全确定自己的理由,但似乎并不完全适用于上述解决方案。我们可以做什么,现在我们已经基于推送的流程正常工作,正在使用reflect
将其转回基于拉取的流程:
-- Preliminary step: switching to '(>~>)'.
stdin >>~ countLettersPush
(const stdin >~> countLettersPush) ()
-- Applying 'reflect', as the documentation suggests.
reflect . (const stdin >~> countLettersPush)
reflect . const stdin <+< reflect . countLettersPush
const (reflect stdin) <+< reflect . countLettersPush
-- Rewriting in terms of '(+>>)'.
(reflect . countLettersPush >+> const (reflect stdin)) ()
reflect . countLettersPush +>> reflect stdin
这确实是基于拉式的,因为流程由reflect stdin
驱动,下游Client
:
GHCi> :t reflect stdin
reflect stdin :: Proxy String () () X IO r
GHCi> :t reflect stdin :: Client String () IO r
reflect stdin :: Client String () IO r :: Client String () IO r
然而,流程涉及向上游发送String
,因此无法用(>->)
来表示,也就是说,仅限于下游:
GHCi> -- Compare the type of the second argument with that of 'reflect stdin'
GHCi> :t (>->)
(>->)
:: Monad m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m