7

haskell.org 上,我遇到了这个自由风格的功能,被称为“猫头鹰”。

((.)$(.))

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

它等效于 f a b c d = a b (c d) 并且显然是 ((.)$(.)) (==) 1 (1+) 0 return True

所以我的问题是:

  1. a1类型签名中的 是什么意思?有关系a吗?
  2. (==)某种函数相等运算符吗?因为0 (==) 0在 GHCi 中引发错误。
  3. 1 (1+) 0在这种情况下是什么意思?我看不出这甚至是一个有效的表达方式。
  4. 为什么表达式返回True
4

2 回答 2

15
  1. a1是“只是另一个类型变量”。它可能意味着任何东西,包括a,但不一定意味着任何东西。很可能与a.

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

  3. 1 (1+) 0在这种情况下并不意味着什么,三个子表达式中的每一个都是“猫头鹰”的独立参数,最终需要四个参数。

  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
    

正如本页所述,owl 相当于一个函数f

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

也就是说,它将其第一个参数(两个参数的函数)应用于其第二个参数,并将其第三个参数应用于其第四个参数的结果。对于给出的示例((.)$(.)) (==) 1 (1+) 0,这意味着您首先应用(+1)0,然后将1(1+0)using结合起来,(==)这就是我们的归约中发生的事情。

更广泛地说,您可能会认为它是一个修改二元运算a以对其第二个参数稍作变化的函数。

于 2013-07-12T05:42:39.400 回答
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  

aanda1是两个不同的类型变量,就像band一样b1。但是由于最终类型中没有bor c,我们可以重命名b1c1返回 just band c,以简化。但不是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' 定义的两次应用(我们总是可以在那里添加我们需要的任意数量的参数)。

于 2013-08-07T16:12:51.290 回答