Haskell 迭代者和FRP之间有什么联系?

Haskell 迭代者和FRP之间有什么联系?,haskell,frp,conduit,iterate,haskell-pipes,Haskell,Frp,Conduit,Iterate,Haskell Pipes,在我看来,这两个想法之间有着紧密的联系。我的猜测是,如果有一种方法可以用迭代对象表示任意图,那么FRP可以用迭代对象来实现。但它们只支持链状结构 有人能解释一下吗?相反。AFRP和流处理之间有着紧密的联系。事实上,AFRP是流处理的一种形式,您可以使用该习惯用法来实现与管道非常类似的功能: data Pipe m a b = Pipe { cleanup :: m (), feed :: [a] -> m (Maybe [b], Pipe m a b)

在我看来,这两个想法之间有着紧密的联系。我的猜测是,如果有一种方法可以用迭代对象表示任意图,那么FRP可以用迭代对象来实现。但它们只支持链状结构


有人能解释一下吗?

相反。AFRP和流处理之间有着紧密的联系。事实上,AFRP是流处理的一种形式,您可以使用该习惯用法来实现与管道非常类似的功能:

data Pipe m a b =
    Pipe {
      cleanup :: m (),
      feed    :: [a] -> m (Maybe [b], Pipe m a b)
    }
这是Netwire中导线类别的扩展。它接收下一个输入块,并在停止生成时不返回任何内容。使用此选项,文件读取器将具有以下类型:

readFile :: (MonadIO m) => FilePath -> Pipe m a ByteString
管道是一个应用函数族,因此要将简单函数应用于流元素,只需使用fmap即可:

为了您的方便,这也是一个ProFunctor家族


最有趣的特性是,这是一系列可选的函子。这使您可以在放弃之前路由流,并允许多个流处理器“尝试”。这可以扩展到一个完整的解析库,甚至可以使用一些静态信息进行优化。

您可以使用流处理器实现有限形式的FRP。例如,使用
管道
库,可以定义事件源:

mouseCoordinates :: (Proxy p) => () -> Producer p MouseCoord IO r
。。。您也可以类似地定义一个图形处理程序,它获取鼠标坐标并更新画布上的光标:

coordHandler :: (Proxy p) => () -> Consumer p MouseCoord IO r
然后使用组合将鼠标事件连接到处理程序:

>>> runProxy $ mouseCoordinates >-> coordHandler
它会按照你期望的方式运行

正如您所说,这对于单级链很有效,但对于更任意的拓扑又如何呢?事实证明,由于中央
代理
类型的
管道
是一个monad转换器,您只需将代理monad转换器嵌套在它们之上,就可以对任意拓扑进行建模。例如,下面是如何压缩两个输入流:

zipD
 :: (Monad m, Proxy p1, Proxy p2, Proxy p3)
 => () -> Consumer p1 a (Consumer p2 b (Producer p3 (a, b) m)) r
zipD () = runIdentityP $ hoist (runIdentityP . hoist runIdentityP) $ forever $ do
    a <- request ()               -- Request from the outer Consumer
    b <- lift $ request ()        -- Request from the inner consumer
    lift $ lift $ respond (a, b)  -- Respond to the Producer

这个技巧可以推广到任何拓扑。您可以在“分支、拉链和合并”一节中找到更多有关这方面的详细信息。特别是,您应该查看它作为示例使用的
fork
组合器,该组合器允许您将流拆分为两个输出。

啊,我正要发布类似的内容,但我将遵从实际编写AFRP库的人的专业知识。:]似乎使用(A)FRP我不会局限于一个非循环图结构,这是真的吗?从你的回答中我不清楚,如果AFRP的任何方面不能用术语或最近拥有流的库导管/管道来实现,会发生什么?我很确定所有sane迭代库都是这样。奥列格不久前用过它。我不知道为什么没有人记得这是可能的;这个技巧非常有用。@JohnL这就是你为什么要宣扬它的原因!不是每个人都知道奥列格做了什么,即使是知道奥列格做了什么的人也常常不明白。可悲的是,我经常在这个小组,至少一开始。。。
zipD
 :: (Monad m, Proxy p1, Proxy p2, Proxy p3)
 => () -> Consumer p1 a (Consumer p2 b (Producer p3 (a, b) m)) r
zipD () = runIdentityP $ hoist (runIdentityP . hoist runIdentityP) $ forever $ do
    a <- request ()               -- Request from the outer Consumer
    b <- lift $ request ()        -- Request from the inner consumer
    lift $ lift $ respond (a, b)  -- Respond to the Producer
-- 1st application
p1 = runProxyK $ zipD   <-< fromListS [1..]

-- 2nd application
p2 = runProxyK $ p2     <-< fromListS [4..6]

-- 3rd application
p3 = runProxy  $ printD <-< p3
>>> p3
(1, 4)
(2, 5)
(3, 6)