[英]How does type unification/function application work at a high level in Haskell?
我觉得我并没有真正了解函数应用程序是如何工作的,或者我可能正在关注一些我不应该做的事情。
让我们尝试确定(fmap .)
的类型签名
fmap :: (x -> y) -> fx -> fy
(.) :: (b -> c) -> (a -> b) -> a -> c -- signatures taken from GHC
将fmap
应用于(.)
,我们本质上想让(x -> y) -> fx -> fy
和(b -> c)
相等。 当我第一次尝试这样做时,我记得有一段非常艰难的时光。 您必须将一组 4 个变量与一组 2 个变量相匹配,所以显然您必须进行一些分组,但是如何? 我看到了 3 种可能的解决方案,它们都有效吗? 还是只有1? 我读到编译器并没有真正考虑括号,所以我们最终得到x -> y -> fx -> fy
和b -> c
,还有与右边相关的函数,所以fmap
实际上应该看起来像x -> (y -> (fx -> fy))
,这导致我
b = x
c = y -> fx -> fy
导致(a -> x) -> (a -> y -> fx -> fy)
作为(fmap .)
的签名。
我已经看到解决这个问题的分组是(a -> b) -> (fa -> fb)
。 所以
b = x -> y
c = fx -> fy
导致(a -> x -> y) -> a -> fx -> fy
,这与 GHC 的(a1 -> a2 -> b) -> a1 -> f a2 -> fb
if 或多或少相同你重命名一些类型变量。
现在比较两个结果,去掉括号:
a -> x -> a -> y -> fx -> fy
a -> x -> y -> a -> fx -> fy
我们可以清楚地看到第 3 和第 4 个参数类型是切换的,这意味着它们显然不一样,因为flip
是一个东西。 这意味着这个替换
b = x
c = y -> fx -> fy
无效。 还是我错过了什么?
我有一种感觉,当我应该反过来做时,我正试图根据签名使函数工作。 :t fmap 'c'
失败, Couldn't match expected type 'a -> b' with actual type 'Char'
这意味着您不能真正部分应用fmap
的a -> b
部分。 您只能部分应用fmap
本身,我猜它的第一个参数是不可分割的。 我不知道我是否得到了这一切背后的模式。
我真的应该尝试编写一个类型化的 lambda 演算。
我看到了 3 种可能的解决方案,它们都有效吗?
不。
还是只有1?
只有一个。 (x -> y) -> fx -> fy
等于(x -> y) -> (fx -> fy)
并且仅是因为->
是右结合的。 把括号放在其他点是错误的。
我读到编译器并没有真正考虑括号,
那是假的。 编译器隐含地工作,因为括号总是以右关联方式添加:类型a -> b -> c -> d
仅作为a -> (b -> (c -> d))
处理。 相比之下,类型(a -> b) -> c -> d
仅被处理为(a -> b) -> (c -> d)
,类型(a -> b -> c) -> d
仅作为(a -> (b -> c)) -> d
处理。
所以我们最终得到
x -> y -> fx -> fy
和b -> c
,
不,那是错误的,你必须保留括号。 我们必须满足类型相等
(x -> y) -> (f x -> f y)
~
b -> c
唯一的解决方案是
b ~ (x -> y)
c ~ (f x -> f y)
正如你后来发现的那样。
要了解统一中发生了什么,我认为如果您从以右关联方式添加隐式括号开始是有益的。 如果你这样做,你可以忘记像a -> b -> c
这样的类型,而只关心基本情况(T -> U)
及其统一步骤:
from (T1 -> U1) ~ (T2 -> U2)
deduce T1 ~ T2 and U1 ~ U2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.