Haskell 中的成分组成
Composition of compositions in Haskell
最近在学习Haskell,是在看Learn You a Haskell中的Functors才知道的
- 接受一个参数的函数
((->)r)
,在某种程度上也是函子。
- 组合
(.)
等同于 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)
这与您在问题中所做的重命名相同。
最近在学习Haskell,是在看Learn You a Haskell中的Functors才知道的
- 接受一个参数的函数
((->)r)
,在某种程度上也是函子。 - 组合
(.)
等同于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)
这与您在问题中所做的重命名相同。