使用应用于(.) 函数组合运算符的“运算符部分的三个规则”,
(.) f g = (f . g) = (f .) g = (. g) f -- the argument goes into the free slot
-- 1 2 3
这可以通过几个简单的机械步骤推导出来:
k x y = (f (g x)) (h y) -- a (b c) === (a . b) c
= (f (g x) . h) y
= (. h) (f (g x)) y
= (. h) ((f . g) x) y
= ((. h) . (f . g)) x y
最后,(.) 是关联的,因此内部括号可能会被删除。
一般的过程是努力达到可以执行 eta-reduction 的情况,即如果它们的顺序相同并且在任何括号之外,我们可以摆脱参数:
k x y = (......) y
=>
k x = (......)
Lather,rinse,重复。
另一个技巧是将两个参数变成一个参数,反之亦然,用等式
curry f x y = f (x,y)
所以,你的
f (g x) (h y) = (f.g) x (h y) -- by B-combinator rule
= (f.g.fst) (x,y) ((h.snd) (x,y))
= (f.g.fst <*> h.snd) (x,y) -- by S-combinator rule
= curry (f.g.fst <*> h.snd) x y
这与answer by @chepner 相同,但更简洁。
所以,你看,你的(f.g <*> h) x1 就变成了(f.g.fst <*> h.snd) (x,y)。相同的区别。
1(因为对于函数,(<$>) = (.))