我在玩弄玩具,我发现了一些有趣的东西:
平凡地,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左右开始吃太多内存。
答案 0 :(得分:37)
我无法解释原因,但这是循环的证明:
假设k >= 2
和fmap^(4k) :: (a -> b) -> F1 F2 F3 a -> F1 F2 F3 b
,其中Fx
代表未知/任意Functor
。 fmap^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 b
和F1 = (->) (a -> b)
必须与F2 F3 (x -> y)
统一
因此F5 a -> F5 b
和F2 = (->) (F5 a)
,即F3 (x -> y) = F5 b
和F5 = 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 -> n
和x = 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 b
,F3 = (->) (a -> b)
和m = F7 a
,因此
n = F7 b
并且循环完成。当然,结果来自查询ghci,但也许这个推导可以解释它是如何工作的。
答案 1 :(得分:2)
我会给出一个稍微简单的答案:map
是fmap
的专精,而(.)
也是 fmap
的特化。因此,通过替换,您将获得您发现的身份!
如果你有兴趣继续前进,Bartosz Milewski有一个很好的writeup使用Yoneda引理明确为什么函数组合是monad。