Haskell 中的成分组成

Composition of compositions in Haskell

最近在学习Haskell,是在看Learn You a Haskell中的Functors才知道的

  1. 接受一个参数的函数((->)r),在某种程度上也是函子。
  2. 组合 (.) 等同于 fmap

据我了解,fmap 有两个参数。第一个是要应用的函数,第二个是函子

但是,我对这个表达式感到困惑(.) (.) (.)。这是两个组合的组合,类型为 (b -> c) -> (a1 -> a2 -> b) -> (a1 -> a2 -> c)

所以这是我的疑问。第一个 (.) 有两个参数,第一个是组合函数本身。第二个参数也是组合函数。并且组合函数本身不是函子。那么这是一个有效的表达式吗?

我确定我在这里遗漏了一些东西。有人可以填补空白并帮助我了解表达式的正确性吗?

忽略 ((->) r)Functor 实例;这是无关紧要的。这里只有两个问题:(.) 的类型,即

(.) :: (b -> c) -> (a -> b) -> a -> c

,以及函数应用 左结合 的事实。后者表示 (.) (.) (.) 等同于 ((.) (.)) (.).

让我们首先尝试找到 (.) (.) 的类型(如果你愿意的话,最左边的)。让我们将第一个 (.) 的类型写为 (b1 -> c1) -> (a1 -> b1) -> a1 -> c1,将第二个写为 (b2 -> c2) -> (a2 -> b2) -> a2 -> c2。我们将第一个应用到第二个,这让我们得到 b1(b2 -> c2)c1(a2 -> b2) -> a2 -> c2。因此我们有

(.) (.) :: (a1 -> (b2 -> c2)) -> a1 -> ((a2 -> b2) -> a2 -> c2)

可以简化为

(.) (.) :: (a1 -> b2 -> c2) -> a1 -> (a2 -> b2) -> a2 -> c2

现在让我们将其应用于最后一个 (.)(如果您愿意,可以是最右边的那个)。如果它有签名 (b3 -> c3) -> (a3 -> b3) -> a3 -> c3,那么我们看到 a1 必须是 (b3 -> c3)b2 必须是 (a3 -> b3) 并且 c2 必须是 a3 -> c3.因此,

((.) (.)) (.) :: (b3 -> c3) -> (a2 -> (a3 -> b3)) -> a2 -> a3 -> c3

相同
((.) (.)) (.) :: (b3 -> c3) -> (a2 -> a3 -> b3) -> (a2 -> a3 -> c3)

这与您在问题中所做的重命名相同。