如果我们首先给组合函数一个更唯一的标识符可能会有所帮助,例如:
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))。由于类型变量不是“全局的”,因此我们可以为类型变量赋予树函数不同的名称:
(.)1 :: (b -> c) -> ((a -> b) -> (a -> c))
(.)2 :: (e -> f) -> ((d -> e) -> (d -> f))
(.)3 :: (h -> i) -> ((g -> h) -> (g -> i))
现在我们已经给不同的组合函数一个签名,我们可以开始派生类型了。
我们知道(.)<sub>2</sub>是带有(.)<sub>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)),因此“返回(.)<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
如果我们用h替换b,用i替换c,用d替换a1,用a替换g,我们得到相同的类型。