重复fmap的乐趣

时间:2012-01-05 02:48:46

标签: haskell functor

我在玩弄玩具,我发现了一些有趣的东西:

平凡地,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 - 嵌套列表上映射函数需要多少fmap个公式?

我尝试编写测试脚本来搜索 n = 4 案例的解决方案,但GHC在40 fmap s左右开始吃太多内存。

2 个答案:

答案 0 :(得分:37)

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

假设k >= 2fmap^(4k) :: (a -> b) -> F1 F2 F3 a -> F1 F2 F3 b,其中Fx代表未知/任意Functorfmap^n代表适用于fmap n-1的{​​{1}},而不是fmap - 倍迭代。导入的开始可以通过手工验证或查询ghci。

n

与 - >统一b产生fmap^(4k+1) = fmap^(4k) fmap fmap :: (x -> y) -> F4 x -> F4 y a = x -> y,所以

b = 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 bF1 = (->) (a -> b)必须与F2 F3 (x -> y)统一 因此F5 a -> F5 bF2 = (->) (F5 a),即F3 (x -> y) = F5 bF5 = F3。结果是

b = 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 -> nx = F6 m,所以

y = 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 bF3 = (->) (a -> b)m = F7 a,因此

n = F7 b

并且循环完成。当然,结果来自查询ghci,但也许这个推导可以解释它是如何工作的。

答案 1 :(得分:2)

我会给出一个稍微简单的答案:mapfmap的专精,而(.) 也是 fmap的特化。因此,通过替换,您将获得您发现的身份!

如果你有兴趣继续前进,Bartosz Milewski有一个很好的writeup使用Yoneda引理明确为什么函数组合是monad。