在 Haskell 中查找组合函数的类型

Finding the type of a composition function in Haskell

假设我在 Haskell 中有以下功能:

compose2 = (.) . (.)

我将如何找到这个函数的类型?由于多种组合,我无法确定此函数的类型。

我知道我可以使用 :t compose2 来获取类型。但是,我想知道如何在没有计算机帮助的情况下做到这一点。我应该采取什么步骤来找到类型?

如果我们先给组合函数一个更独特的标识符可能会有所帮助,例如:

compose2 = (.)<sub>2</sub> .<sub>1</sub> (.)<sub>3</sub>

这样更容易引用某些函数。我们还可以将其转换为更规范的形式,例如:

compose2 = ((.)<sub>1</sub> (.)<sub>2</sub>) (.)<sub>3</sub>

所以现在我们可以开始推导函数类型了。我们知道 (.) 有类型 (.) :: (b -> c) -> (a -> b) -> a -> c,或者更规范的 (.) :: (b -> c) -> ((a -> b) -> (a -> c))。由于类型变量不是“全局”的,因此我们可以为树函数赋予类型变量不同的名称:

(.)<sub>1</sub> :: (b -> c) -> ((a -> b) -> (a -> c))
(.)<sub>2</sub> :: (e -> f) -> ((d -> e) -> (d -> f))
(.)<sub>3</sub> :: (h -> i) -> ((g -> h) -> (g -> i))

现在我们已经为不同的组合函数赋予了签名,我们可以开始推导类型了。

我们知道(.)<sub>2</sub>是用(.)[=函数应用的参数68=]1</sub>,所以这意味着参数的类型 (b -> c) 与类型 (e -> f) -> ((d -> e) -> (d -> f)) 相同,因此 b ~ (e -> f),和 c ~ ((d -> e) -> (d -> f)).

我们进一步知道 (.)<sub>1</sub> 的“第二个”参数的类型与 (.)<sub>3</sub>,因此 (a -> b) ~ ((h -> i) -> ((g -> h) -> (g -> i))),因此 a ~ (h -> i),以及 b ~ ((g -> h) -> (g -> i)),因此“return type" of (.)<sub>1</sub>,即 (a -> c) 因此可以特化为:

((.)<sub>1</sub> (.)<sub>2</sub>) (.)<sub>3</sub> :: a -> c

并且由于 a ~ (h -> i),并且 c ~ (d -> e) -> (d -> f):

((.)<sub>1</sub> (.)<sub>2</sub>) (.)<sub>3</sub> :: (h -> i) -> ((d -> > e) -> (d > f))

我们知道 b 等价于 b ~ (e -> f)b ~ ((g -> h) -> (g -> i)),所以这意味着 e ~ (g -> h)f ~ (g -> i),因此我们可以专门化签名进一步到:

((.)<sub>1</sub> (.)<sub>2</sub>) (.)<sub>3</sub> :: (h -> i) -> ((d -> (g -> h)) -> (d -> (g -> i)))

这是更详细的形式:

(.)<sub>2</sub> .<sub>1</sub> (.)<sub>3</sub> :: (h -> i) -> (d -> g -> h) -> d -> g -> i

如果我们自动推导类型,我们得到:

Prelude> :t (.) . (.)
(.) . (.) :: (b -> c) -> (a1 -> a -> b) -> a1 -> a -> c

如果我们因此将 b 替换为 h,将 c 替换为 i,将 a1 替换为 da使用g,我们得到相同的类型。