【问题标题】:How does mapA work with a Stream Function Arrow in Haskell?mapA 如何与 Haskell 中的流函数箭头一起使用?
【发布时间】:2014-04-13 20:32:26
【问题描述】:

背景

我一直在浏览 John Hughes 的Programming with Arrows,我觉得我的一切都在我的脑海中,直到以下使用 mapA 的示例:

>runSF (mapA (delay 0)) [[1,2,3],[4,5,6],[7,8,9]]
[[0,0,0],[1,2,3],[4,5,6]]

其中 runSF 从 StreamFunction 箭头中提取流函数定义为:

newtype SF a b = SF {runSF :: [a]->[b]}

而延迟定义为:

delay x = SF (init . (x:))

SF 是 ArrowChoice 的一个实例(它声明了 mapA),因此也是一个 Arrow 的实例。

我的理解

mapA :: arr a b -> arr [a] [b]
delay :: SF a b

这样delay 只需将其第二个参数添加到第一个参数之前。

因此,mapA (delay 0) 应该返回给我们一个 SF 箭头,它接受 [[a]] 并返回 [[b]]

mapA (delay 0) :: SF [[a]] [[b]]

我希望这会导致的“电路”是:

数字标记流程的各个部分:

  1. 对于任何非空的list xlistcase 将发出Right(x, xs)。对于空列表,listcase 将发出 Left(),即终端情况。
  2. 标记为Right 的值将传递到下部。标记为 Left 的值将传递给 const[],这实际上会停止迭代。
  3. 输入(x, xs)x 将被传递给(delay 0),而xs 将被传递回listcase
  4. 3 的输出将是(z, zs),它被传递给uncurry (:),后者将元组重新加入到列表中。

这是我对流程的理解,输入[[1,2,3],[4,5,6],[7,8,9]]

  • 第一关

    1. Right ([1,2,3],[[4,5,6],[7,8,9]])
    2. ([1,2,3], [[4,5,6],[7,8,9]]) 被传递到下部
    3. [1,2,3] 上调用(delay 0),产生[0,1,2][[4,5,6],[7,8,9]] 被传回listcase
  • 第二遍

    1. Right ([4,5,6], [[7,8,9]])
    2. ([4,5,6], [[7,8,9]]) 被传递到下部
    3. [4,5,6] 上调用(delay 0),产生[0,4,5][[7,8,9]] 被传回listcase
  • 第三遍

    1. Right ([7,8,9], [])
    2. ([7,8,9], []) 被传递到下部
    3. [7,8,9] 上调用(delay 0),产生[0,7,8][] 被传回给listcase
  • 第四关

    1. Left (),掉在地上。

此时,我们进入第 4 部分,它获取 3 的输出并将它们连接在一起。我们基本上构建了以下操作:

[0,1,2] : [[0,4,5] : [[0,7,8] : []]]

这会给我们[[0,1,2],[0,4,5],[0,7,8]]

我的困惑

显然,我上面的流程是错误的。

调用runSF (mapA (delay 0)) [[1,2,3],[4,5,6],[7,8,9]] 是如何产生[[0,0,0],[1,2,3],[4,5,6]] 的?

【问题讨论】:

  • 好吧,显然我的理解是错误的,因为延迟的类型是 SF。不是函数本身。

标签: haskell arrows


【解决方案1】:

我发现这些例子很难推理。这里面有两个列表 例如,外部列表是您的箭头操作的流,而 内部列表是 mapA 映射的内容。考虑一个更简单的例子,所以我们 现在可以忽略递归情况。给定

runSF (mapA (delay 0)) [[1], [2]]

我们看到第一步

  1. 将输入通过listcase 箭头传递给我们输出 [Right (1, []), Right (2, [])]。每对的第一个元素 被送入delay 0 箭头,而第二个元素被送入 回mapA f
  2. 所以,我们有[1, 2] => delay 0[[], []] => mapA f。 将[1,2] 输入delay 0 会得到[0, 1] 的结果,并且 将空列表提供给 mapA f 会产生更多空列表 [[], []]
  3. 这两个结果被馈送到arr (uncurry (:)),其行为类似于zipWith (:), 因为这些函数都映射到列表上,所以它加入了两个输入 按元素列出。

    [0,  1]
       |
       v
    arr (uncurry (:)) => [ 0:[], 1:[] ] == [[0], [1]]
       ^
       |
    [[], []]
    

关键是要认识到用arr 构造的所有东西都在运行 内部列表集,因此通过arr listcase 运行您的初始输入 不会产生Right ([1,2,3],[[4,5,6],[7,8,9]]),但是 [Right (1, [2, 3]), Right (4, [5,6]), Right (7, [8,9])]。 这是我尝试在图表中绘制出来的。

     [Right (1, [2, 3]), Right (4, [5,6]), Right (7, [8,9])]
     =======================================================
                 |        [1, 4, 7]      +-----------+ [0, 1, 4]
  +----------+   |       +----=--------->|   delay   |-----=------|
  | listcase |---=------>|               +-----------+            |   +-------------------+
  +----------+           |                                        +-->| arr (uncurry (:)) |---> [[0,0,0],[1,2,3],[4,5,6]]
                         |                                        |   +-------------------+
                         |               +-----------+            |
                         +-------=------>|   mapA f  |------=-----|
                                 |       +-----------+      |
                                 |                          |
                          [[2,3],[4,5],[6,7]]         [[0,0], [2,3],[4,5]]
                                                      * what will be
                                                        returned if you
                                                        trace it through

抱歉,我画的不好。实际上,mapA 给出了一个转置的视图 输入列表,所以你可以认为mapA (delay 0) 像这样操作 transpose . map (init . (0:)) . transpose,因为 init . (0:)delay的定义。

【讨论】:

  • 非常感谢!是的,我现在意识到我完全忽略了 listcase 被提升为 SF 箭头。您的图表和简单的演练使这非常有帮助。谢谢!
  • 最后...所有这些乱七八糟的东西都被彻底剖析了.. :) 非常感谢!!!您描述了主要错误 - 对 listcаse 所做的事情的错误解释(我没有注意到 listcase 被提升为 SF 只是将自己映射到输入列表的每个元素) - 在澄清这个事实之后一切整理好了..
猜你喜欢
  • 2021-04-07
  • 2020-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
  • 2015-11-15
相关资源
最近更新 更多