【问题标题】:What is the connection between Iteratees and FRP?Iteratees和FRP之间有什么联系?
【发布时间】:2012-12-04 22:25:52
【问题描述】:

在我看来,这两个想法之间有很强的联系。我的猜测是,如果有一种方法可以用 Iteratees 表达任意图,那么 FRP 可以根据 Iteratees 来实现。但是 afaik 他们只支持链状结构。

有人能解释一下吗?

【问题讨论】:

    标签: haskell frp conduit iterate haskell-pipes


    【解决方案1】:

    情况正好相反。 AFRP 和流处理之间有很强的联系。其实AFRP一种流处理的形式,你可以用这个成语来实现和管道很相似的东西:

    data Pipe m a b =
        Pipe {
          cleanup :: m (),
          feed    :: [a] -> m (Maybe [b], Pipe m a b)
        }
    

    这是 Netwire 中电线类别的扩展。它接收下一个输入块,并在停止生成时返回 Nothing。使用此文件阅读器将具有以下类型:

    readFile :: (MonadIO m) => FilePath -> Pipe m a ByteString
    

    Pipe 是一系列应用函子,因此要将一个简单的函数应用于流元素,您只需使用 fmap

    fmap (B.map toUpper) . readFile
    

    为了您的方便,它也是一个profunctors。

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

    【讨论】:

    • 啊,我正要发布类似的东西,但我会听从实际编写 AFRP 库的人的专业知识。 :]
    • 看来使用(A)FRP我不会局限于非循环图结构,是这样吗?
    • 从你的回答中我不清楚如果 AFRP 的任何方面不能用术语或最近拥有库管道/管道的流来实现怎么办?
    【解决方案2】:

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

    mouseCoordinates :: (Proxy p) => () -> Producer p MouseCoord IO r
    

    ...您可以类似地定义一个图形处理程序,该处理程序获取鼠标坐标并更新画布上的光标:

    coordHandler :: (Proxy p) => () -> Consumer p MouseCoord IO r
    

    然后您将使用组合将鼠标事件连接到处理程序:

    >>> runProxy $ mouseCoordinates >-> coordHandler
    

    它会按照您期望的方式运行。

    正如您所说,这适用于单个阶段链,但是更任意的拓扑呢?好吧,事实证明,由于pipes 的中心Proxy 类型是一个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
    

    这表现得像一个柯里化函数。您可以按顺序将其部分应用到每个输入,然后在完全应用后运行它。

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

    这个技巧可以推广到任何拓扑。您可以在“分支、压缩和合并”部分的 Control.Proxy.Tutorial 中找到更多详细信息。特别是,您应该查看它用作示例的 fork 组合器,它可以让您将一个流拆分为两个输出。

    【讨论】:

    • 我很确定所有理智的迭代库都是如此。奥列格前段时间使用过它。我不确定为什么似乎没有人记得这是可能的。该技术非常有用。
    • @JohnL 这就是为什么你必须宣讲它!不是每个人都知道奥列格做了什么。
    • 即使知道奥列格做了什么的人也常常不明白。可悲的是,我经常在这个小组中,至少一开始是……
    猜你喜欢
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多