Haskell:为什么((.).(.)) f g等同于f.g x?

8

您能解释一下表达式 ((.).(.)) 的含义吗?据我所知,(.) 具有类型 (b -> c) -> (a -> b) -> a -> c。


3
"((.).(.)) f g" 不等于 "f . g x"(但是 "((.).(.)) f g x" 相等)。 - Frerich Raabe
2个回答

23

(.) . (.) 是将组合运算符与其自身进行组合的结果。

如果我们观察一下

((.) . (.)) f g x

我们可以分几步来评估,首先加上括号:
((((.) . (.)) f) g) x

然后,我们使用 (foo . bar) arg = foo (bar arg) 进行应用:
~> (((.) ((.) f)) g) x
~> (((.) f) . g) x
~> ((.) f) (g x)
~> f . g x

更有原则性,
(.) :: (b -> c) -> (a -> b) -> (a -> c)

因此,在使用(.)作为(.)的第一个参数时,我们必须进行统一。
b -> c

使用

(v -> w) -> (u -> v) -> (u -> w)

这将产生的结果是:
b = v -> w
c = (u -> v) -> (u -> w)

并且

(.) (.) = ((.) .) :: (a -> v -> w) -> a -> (u -> v) -> (u -> w)

现在,要将这个应用到(.)上,我们必须统一类型。
a -> v -> w

使用类型为(.)的变量,在重命名后

(s -> t) -> (r -> s) -> (r -> t)

这将产生

a = s -> t
v = r -> s
w = r -> t

因此

(.) . (.) :: (s -> t) -> (u -> r -> s) -> (u -> r -> t)

从类型中我们可以(几乎)看出(.) . (.)将对两个参数的函数结果应用一个函数(只有一个参数)。


2
你已经得到了一个答案,这里稍微有些不同的看法。在组合逻辑中,(.)B-combinator : Babc = a(bc)。在编写组合表达式时,惯例是假定每个标识符仅包含一个字母,并省略应用中的空格,以使表达式更易读。当然,通常的柯里化也适用: abcde(((ab)c)d)e,反之亦然。(.)B,因此((.) . (.)) == (.) (.) (.) == BBB。所以,
BBBfgxy = B(Bf)gxy = (Bf)(gx)y = Bf(gx)y = (f . g x) y    
 abc        a  bc                 a b  c                  

我们可以抛掉结尾的两个 y (这被称为 eta-reduction:如果 y 不出现在 H 中,则 Gy=Hy --> G=H)。但是,另一种呈现方式是:
BBBfgxy = B(Bf)gxy = ((f .) . g) x y = f (g x y)     -- (.) f == (f .)
-- compare with:       (f .) g x = f (g x)

"

((f .) . g) x y可能比((.).(.)) f g x y更容易输入,但你的体验可能有所不同。

"
例如,对于S组合子,其定义为Sfgx = fx(gx),如果不考虑这个规则,我们可以写成:
Sfgx = fx(gx) = B(fx)gx = (f x . g) x
Sfg = B(fx)g = (f x . g)   --- WRONG, what is "x"?

这是无稽之谈。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接