在 Haskell 中,所有函数都采用一个输入参数。但有时,应用函数的返回值是一个新函数。那么,第一步,您可以通过将函数的返回值放在括号中来使其更加明确f
and g
:
f :: Par -> (a -> b)
g :: Par -> (b -> c)
函数也是类型,所以我们可以任意决定别名a -> b
to φ
(phi代替f) and b -> c
to γ
(gamma代替g)。 (是的,当你用完字母时,你就可以使用希腊字母!)
这意味着您可以将您的函数视为具有以下类型
f :: Par -> φ
g :: Par -> γ
这些都是所谓的自动实例读者单子,这也是一个(应用)函子。特别,(->) Par
,或者,如果有帮助的话,Par ->
, is an Applicative
实例。这意味着您可以使用pure
and <*>
用它。
作为第一次尝试,您可以写类似的内容
pure (\x y -> (x, y)) <*> f <*> g
为了简单地理解该组合物是如何工作的。该表达式的类型为Par -> (φ, γ)
, 可以这么说。该 lambda 表达式只需x
来自f
“容器”,以及y
来自g
'容器',并将它们组合在一个元组中。元组的第一个元素的类型为φ
,第二个元素的类型为γ
.
代入定义φ
and γ
,你得到类型Par -> (a -> b, b -> c)
.
您想要组合这些函数,而不是作为函数元组的返回值。您可以使用函数组合运算符.
为了那个原因:
h = pure (\x y -> y . x) <*> f <*> g
请注意,函数是从右到左组成的,因此x
(a -> b
) 首先出现,然后是y
(b -> c
).
但是,您可以翻转f
and g
around:
h = pure (\y x -> y . x) <*> g <*> f
然后,该显式 lambda 表达式可以被 eta 简化为:
h = pure (.) <*> g <*> f
最后,而不是写pure (.) <*>
你可以使用中缀<$>
操作员:
h = (.) <$> g <*> f
该函数的类型为Par -> a -> c
.