Haskell中bisequence与bitraverse的等价关系及类型匹配困惑
理解Haskell中bisequence与bitraverse的等价关系
核心结论:bisequence ≡ bitraverse id id的等价性本质是类型参数的实例化匹配,你的两个困惑都源于没把id的类型和bitraverse的参数类型做统一替换。
解答第一个困惑:id为什么能适配a -> f c类型
id的类型签名是forall a. a -> a,这是一个多态类型——Haskell会根据上下文自动实例化其中的类型变量。当把id传给bitraverse的第一个参数(要求类型是x -> f y)时,Haskell会把id的类型变量a实例化为f a'(用a'避免和原类型混淆),此时id的类型就变成了f a' -> f a',完全符合x -> f y的要求(x是f a',y是a',f就是原Applicative的f)。
同理,传给第二个参数的id会被实例化为f b' -> f b',完美匹配bitraverse的第二个参数类型b -> f d。
解答第二个困惑:类型签名为什么能匹配
当我们把两个id都按上面的方式实例化后,再推导bitraverse id id的类型:
bitraverse的原始类型是Applicative f => (a -> f c) -> (b -> f d) -> t a b -> f (t c d)- 代入第一个参数
id :: f a -> f a,意味着bitraverse的第一个类型变量a被替换为f a,c被替换为a - 代入第二个参数
id :: f b -> f b,意味着bitraverse的第一个类型变量b被替换为f b,d被替换为b - 替换后,
bitraverse id id的类型就变成了:(Bitraversable t, Applicative f) => t (f a) (f b) -> f (t a b)
这和bisequence的类型签名完全一致,输入的t (f a) (f b)正好对应bisequence的输入类型,输出也完全匹配。
简单说,就是通过给id的多态类型绑定具体的实例,让bitraverse的输入类型自动带上了Applicative层,最终和bisequence的类型对齐。
内容的提问来源于stack exchange,提问作者jacobsa
相关产品推荐
相关产品推荐

