f3 g x = let h y = f3 g (g y) in g x
我们先看一个更简单的版本:
f3' g x = g x
这里g应用于x,g的结果变成f3'的结果。所以f3'的类型是(a -> b) -> a -> b。
完整的f3 包含子表达式f3 g (g y),它引入了一些额外的约束:f3 g 是无害的(没有额外的约束,因为g 是我们在开始时调用的参数),但是(如您在问题中说)将g y 作为第二个参数传递意味着g 的结果必须与x(第二个参数)具有相同的类型。
这意味着a = b,因此是f3 :: (a -> a) -> a -> a。
在你的第二个例子中,我们有
f4 g x = let h y = f4 g (g y) in x
没有let,只是:
f4' g x = x
类型为a -> b -> b。
完整的f4 包含f4 g (g y)。一方面,这意味着g 必须是一个函数(因为它应用于y),所以我们的约束集如下所示:
f4 :: a -> b -> b
g :: a
x :: b
g :: c -> d
a = c -> d
那么(g y)被用作f4的第二个参数,这意味着它的类型必须等于b:
g y :: b
g :: c -> b
y :: c
d = b
h 未使用,因此y 或f4 上没有附加限制。代入f4类型的变量,我们得到
f4 :: (c -> b) -> b -> b
(相当于(t1 -> t) -> t -> t取模命名)。