能否有人解释一下 ((.)$(.)) (==) 1 (1+) 0 的含义?

7
我在 Haskell.org 上发现了这个点无风格函数,被称为“the owl”。
((.)$(.))

它的类型签名是 (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c

它等价于 f a b c d = a b (c d) 而且, ((.)$(.)) (==) 1 (1+) 0 返回True

所以我的问题是:

  1. 类型签名中的a1是什么意思?它和a有关吗?
  2. (==)是某种函数相等运算符吗?因为在GHCi中执行0 (==) 0会抛出错误。
  3. 在这个上下文中,1 (1+) 0是什么意思?我不明白这甚至是一个有效的表达式。
  4. 为什么这个表达式返回True

2
请注意,在 ((.)$(.)) 中的 $ 是不必要的;表达式 ((.)(.)) 完全等效。 - Chris Taylor
2个回答

15
  1. a1是"另一个类型变量",它可以表示任何东西,包括a,但不一定表示任何东西。很可能它与a不同。

  2. (==)Eq类型类中常规等式运算符==的"强制前缀"形式。通常你会写a == b,但那只是==的前缀应用的语法糖,即(==) a b

  3. 1 (1+) 0在这个上下文中没有特殊意义,其中的每个子表达式都是"the owl(猫头鹰)"的独立参数,最终接收四个参数。

  4. 我们可以遍历这个规约过程。

((.)$(.)) (==) 1 (1+) 0
===                          [ apply ]
((.)(.)) (==) 1 (1+) 0
===                          [ implicit association ]
((.)(.)(==)) 1 (1+) 0
===                          [ apply the definition: (f.g) x = f (g x) ]
((.) (1 ==)) (1+) 0
===                          [ implicit association ]
((.) (1 ==) (1+))  0
===                          [ apply the definition: (f.g) x = f (g x) ]
1 == (1+0)
===                          [addition]
1 == 1
===                          [equality]
True

正如这个页面所提到的,猫头鹰相当于一个名为 f 的函数。

f a b c d = a b (c d)

也就是说,它将其第一个参数(一个接受两个参数的函数)应用于其第二个参数和将其第三个参数应用于其第四个参数的结果。对于给定的例子((.)$(.)) (==) 1 (1+) 0,这意味着您首先将(+1)应用于0,然后使用(==)1(1+0)组合在一起,这就是我们缩减中发生的事情。

更广泛地说,您可以将其视为修改二元运算a以对其第二个参数进行轻微变化的函数。


我明白了,我忘记了强制前缀。我以为这是普通括号。感谢您的评估指导。 - Senjougahara Hitagi
2
Nit: (==) 1 应该是 (1 ==),而不是 (== 1)。虽然对于 == 的默认定义来说这并没有什么关系... - Andreas Rossberg

1

首先,让我们写出_B f g x = f (g x) = (f . g) x

由于 f $ x = f x,因此我们有 (.)$(.) = _B $ _B = _B _B。它的类型是机械地推导出来的,如下所示:

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

1. (.) ::  (b1 -> c1) -> ((a1 -> b1) -> (a1 -> c1))

2. (.) (.) :: {b ~ b1 -> c1, c ~ (a1 -> b1) -> (a1 -> c1)} (a -> b) -> (a -> c)

           :: (a -> b1 -> c1) -> a -> (a1 -> b1) -> (a1 -> c1)
           :: (a -> b  -> c ) -> a -> (a1 -> b ) ->  a1 -> c  

aa1是两个不同的类型变量,就像bb1一样。但由于最终类型中没有bc,我们可以将b1c1重新命名为bc,以简化问题。但不能将a1重新命名。

实际上,我们可以看懂这种类型:它接收一个二元函数f :: a -> b -> c,一个参数值x :: a,一个一元函数g :: a1 -> b和另一个值y :: a1,并以唯一可能的方式组合它们,以使类型匹配。

    f x       :: b -> c
    g y       :: b
    f x (g y) ::      c

其余部分已经回答。缩减通常更容易在组合方程中理解,例如_B _B f x g y = _B (f x) g y = f x (g y),只需使用_B的定义进行两次应用(我们可以随时添加所需的参数)。

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