【问题标题】:Fun with repeated fmap重复 fmap 的乐趣
【发布时间】:2012-02-02 22:51:22
【问题描述】:

我在玩仿函数,发现了一些有趣的东西:

简单地说,id 可以被实例化为 (a -> b) -> a -> b 类型。

使用列表函子我们有fmap :: (a -> b) -> [a] -> [b],它与map 相同。

对于((->) r)函子(来自Control.Monad.Instances),fmap是函数组合,所以我们可以实例化fmap fmap fmap :: (a -> b) -> [[a]] -> [[b]],相当于(map . map)

有趣的是,fmap 八次给了我们(map . map . map)

所以我们有

0: id = id
1: fmap = map
3: fmap fmap fmap = (map . map)
8: fmap fmap fmap fmap fmap fmap fmap fmap = (map . map . map)

这种模式会继续吗?为什么/为什么不?是否有一个公式来计算我需要将函数映射到 n 次嵌套列表上的 fmaps 数量?

我尝试编写一个测试脚本来寻找 n = 4 情况的解决方案,但 GHC 在大约 40 fmaps 时开始占用过多内存。

【问题讨论】:

  • 它很快退化成一个循环或类似的东西,但我忘记了确切的公式。 (顺便说一句,lambdabot 实际上将(.) 定义为fmap。)
  • @ehird:我认为你是对的。似乎fmap n = 4k 次(对于 n 至少 8)给出了(map . map . map)。不过,我仍然很好奇为什么会发生这种情况。特别是因为实例发生了变化。 n = 8 时为(.) (.) (.) (.) (.) map map map,而n = 12 时为(.) (.) (.) (.) (.) (.) (.) (.) map (.) map map

标签: haskell functor


【解决方案1】:

我无法解释原因,但这是循环的证明:

假设k >= 2fmap^(4k) :: (a -> b) -> F1 F2 F3 a -> F1 F2 F3 b,其中Fx 代表未知/任意Functorfmap^n 代表 fmap 应用于 n-1 fmaps,而不是 n-fold 迭代。感应的开始可以手动验证或查询 ghci。

fmap^(4k+1) = fmap^(4k) fmap
fmap :: (x -> y) -> F4 x -> F4 y

与 a -> b 统一产生a = x -> yb = F4 x -> F4 y,所以

fmap^(4k+1) :: F1 F2 F3 (x -> y) -> F1 F2 F3 (F4 x -> F4 y)

现在,对于fmap^(4k+2),我们必须将F1 F2 F3 (x -> y)(a -> b) -> F5 a -> F5 b 统一起来。
因此F1 = (->) (a -> b)F2 F3 (x -> y)必须与F5 a -> F5 b统一。
因此F2 = (->) (F5 a)F3 (x -> y) = F5 b,即F5 = F3b = x -> y。结果是

fmap^(4k+2) :: F1 F2 F3 (F4 x -> F4 y)
             = (a -> (x -> y)) -> F3 a -> F3 (F4 x -> F4 y)

对于fmap^(4k+3),我们必须统一a -> (x -> y)(m -> n) -> F6 m -> F6 n),得到a = m -> n
x = F6 my = F6 n,所以

fmap^(4k+3) :: F3 a -> F3 (F4 x -> F4 y)
             = F3 (m -> n) -> F3 (F4 F6 m -> F4 F6 n)

最后,我们必须统一F3 (m -> n)(a -> b) -> F7 a -> F7 b,所以F3 = (->) (a -> b)m = F7 an = F7 b,因此

fmap^(4k+4) :: F3 (F4 F6 m -> F4 F6 n)
             = (a -> b) -> (F4 F6 F7 a -> F4 F6 F7 b)

循环完成。当然,结果来自查询 ghci,但也许推导对它的工作原理有一些启发。

【讨论】:

    【解决方案2】:

    我将给出一个稍微简单的答案:mapfmap 的特化,(.)也是fmap 的特化。所以,通过替换,你得到了你发现的身份!

    如果您有兴趣更进一步,Bartosz Milewski 有一个很好的 writeup,它使用米田引理来明确说明为什么函数组合是一个单子。

    【讨论】:

      猜你喜欢
      • 2015-04-13
      • 1970-01-01
      • 1970-01-01
      • 2017-02-08
      • 2010-12-24
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      相关资源
      最近更新 更多