直觉上很明显,以下法律应该成立:
traverse f . fmap g = traverse (f . g)
似乎直接申请的唯一Traversable
法律是
fmap g = runIdentity . traverse (Identity . g)
将问题更改为
traverse f . runIdentity . traverse (Identity . g)
唯一适用于此的模糊形式的法则是自然法。然而,那是关于应用变换的,我没有看到任何这些变换。
除非我遗漏了什么,否则唯一剩下的就是参数化证明,而我还没有弄清楚如何写这些。
答案 0 :(得分:6)
请注意,这个证明实际上并不是必需的,因为所讨论的结果确实是一个自由定理。请参阅Reid Barton的回答。
我相信这样做:
traverse f . fmap g -- LHS
根据fmap/traverse
法律,
traverse f . runIdentity . traverse (Identity . g)
fmap
的{{1}}实际上是Identity
,
id
runIdentity . fmap (traverse f) . traverse (Identity . g)
法律提供了将两个遍历合并为一个的方法,但我们必须首先使用Compose
引入Compose
。
getCompose . Compose = id
再次使用runIdentity . getCompose . Compose . fmap (traverse f) . traverse (Identity . g)
-- Composition law:
runIdentity . getCompose . traverse (Compose . fmap f . Identity . g)
Identity
,
fmap
runIdentity . getCompose . traverse (Compose . Identity . f . g)
是一种应用转型,因此本质上是
Compose . Identity
折叠反转,
runIdentity . getCompose . Compose . Identity . traverse (f . g)
为了完整起见,引用法律和推论:
traverse (f . g) -- RHS
后一事实遵循身份法-- Composition:
traverse (Compose . fmap g . f) = Compose . fmap (traverse g) . traverse f
-- Naturality:
t . traverse f = traverse (t . f) -- for every applicative transformation t
-- `fmap` as traversal:
fmap g = runIdentity . traverse (Identity . g)
,加上traverse Identity = Identity
的唯一性。
答案 1 :(得分:4)
根据lambdabot,它是一个自由定理(参数)。
响应@free traverse :: (a -> F b) -> T a -> F (T b)
,lamdabot产生
$map_F g . h = k . f => $map_F ($map_T g) . traverse h = traverse k . $map_T f
设置g = id
以便h = k . f
。然后结论变成
traverse (k . f) = traverse k . fmap f