在Haskell中,类型统一/函数应用程序在高层次上是如何工作的?

wtlkbnrh  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(95)

我觉得我没有真正了解函数应用程序是如何工作的,或者我可能在关注一些我不应该关注的事情。
让我们尝试确定(fmap .)的类型签名
fmap :: (x -> y) -> f x -> f y
(.) :: (b -> c) -> (a -> b) -> a -> c -- signatures taken from GHC
fmap应用到(.),我们基本上想使(x -> y) -> f x -> f y(b -> c)相等。当我第一次尝试这样做的时候,我记得我有一段非常困难的时间。你必须将一组4个变量与一组2个变量相匹配,所以显然你必须进行一些分组,但是怎么做呢?我看到有3种可能的解决方案,它们都有效吗?还是只有1?我读到编译器没有真正考虑括号,所以我们最终得到了x -> y -> f x -> f yb -> c,还有与右边关联的函数,所以fmap实际上应该看起来像x -> (y -> (f x -> f y)),这就导致了
b = x
c = y -> f x -> f y
从而产生(a -> x) -> (a -> y -> f x -> f y)作为(fmap .)的签名。
我看到的解决这个问题的分组是(a -> b) -> (f a -> f b)
b = x -> y
c = f x -> f y
导致(a -> x -> y) -> a -> f x -> f y,如果重命名一些类型变量,它或多或少与GHC的(a1 -> a2 -> b) -> a1 -> f a2 -> f b相同。
现在要比较2个结果,删除括号:
x1米20英寸
a -> x -> y -> a -> f x -> f y
我们可以清楚地看到,第3个和第4个参数类型被交换了,这意味着它们显然是不一样的,因为flip是一个东西。
b = x
c = y -> f x -> f y
是无效的。还是我遗漏了什么?
我有一种感觉,我试图让函数基于签名工作,而我应该以相反的方式工作。:t fmap 'c'Couldn't match expected type 'a -> b' with actual type 'Char'上失败,这意味着你不能真正部分地应用fmapa -> b部分。你只能部分地应用fmap本身,我猜它的第一个参数是不可分的。我不知道我是否'不过,我已经知道这背后的规律了。
我真的应该试着写一个类型化的lambda演算。

3okqufwl

3okqufwl1#

我看到了3种可能的解决方案,它们都有效吗?
不,不,不
还是只有1?
只有一个。(x -> y) -> f x -> f y等于(x -> y) -> (f x -> f y),而且只等于(x -> y) -> (f x -> f y),因为->是右结合的。在其他点上加括号是错误的。
我读到编译器并没有真正考虑括号,
这是错误的。编译器隐式地工作,因为括号总是以右关联的方式添加:类型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 -> f x -> f yb -> 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

相关问题