在haskell.org我遇到了这个点自由风格的功能,被称为“猫头鹰”。
((.)$(.))
它的类型签名是
(a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
。
相当于
f a b c d = a b (c d)
显然,
((.)$(.)) (==) 1 (1+) 0
返回True
。
所以我的问题是:
a1
是什么意思?它与a
?(==)
是某种函数相等运算符吗?因为0 (==) 0
在GHCi中引发错误。1 (1+) 0
在这种情况下的含义是什么?我不知道这甚至是一个有效的表达方式。True
?答案 0 :(得分:15)
a1
是“只是另一种类型变量”。它可能意味着什么,包括a
,但并不一定意味着什么。最有可能与a
不同。
(==)
是来自==
类型类的Eq
正则相等运算符的“强制前缀”形式。通常你会写a == b
,但这只是(==) a b
的语法糖,==
的前缀应用。
1 (1+) 0
在这种情况下并不意味着什么,三个子表达式中的每一个都是“猫头鹰”的独立参数,最终需要四个参数。
我们可以逐步完成减少。
((.)$(.)) (==) 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
如this page所述,猫头鹰等同于函数f
f a b c d = a b (c d)
也就是说它将第一个参数(两个参数的函数)应用于其第二个参数以及将其第三个参数应用于其第四个参数的结果。对于给定((.)$(.)) (==) 1 (1+) 0
的示例,这意味着您首先将(+1)
应用于0
,然后使用1
合并(1+0)
和(==)
发生在我们的减少。
更广泛地说,您可能会将其视为一个修改二元操作a
的函数,以便对其第二个参数稍作修改。
答案 1 :(得分:0)
首先,让我们写_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
a
和a1
是两个不同的类型变量,就像b
和b1
一样。但由于最终类型中没有b
或c
,我们可以将b1
和c1
重命名为b
和{{1} ,简化。但不是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)
),组合方程式中的减少通常更容易遵循(我们总是可以添加与我们一样多的参数需要)。