2014-12-27 59 views
1

我想翻转列表构造函数的用法,有类型:Haskell应用程序或部分?

[a] -> a -> [a] 

(用于折叠使用),所以尝试:

(flip :) 

,但它给人的类型:

Prelude> :t (flip :) 
(flip :) :: [(a -> b -> c) -> b -> a -> c] -> [(a -> b -> c) -> b -> a -> c] 

这让我感到惊讶,但它似乎被解析为(:)的左侧部分,而不是部分应用翻盖。重写它采用翻盖作为缀似乎克服这一点,

Prelude> :t ((:) `flip`) 
((:) `flip`) :: [a] -> a -> [a] 

但我找不到定义这种行为的规则,我认为的功能应用最高优先级,并且评价左>右,所以我预料这两种形式是等同的。

回答

3

它将:放在使您的第二个示例工作的括号内,而不是在flip附近使用反引号。

我们经常说“功能应用程序具有最高优先级”以强调例如, f x + 1应该被读作(f x) + 1,而不是f (x + 1)。但这并不完全准确。如果是,并且(flip :)按照预期进行了解析,那么在(f x) + 1之后的最高优先级将是(f x)+的应用;整个表达式f x + 1最终将被解析为应用于3个参数的fx,+1。但是所有涉及中缀操作符的表达式都会发生这种情况!即使是一个简单的1 + 1将被识别为1适用于+1(然后抱怨缺少的Num实例将允许1是一个函数)。

从本质上讲,对“功能应用程序具有最高优先级”的这种严格理解意味着功能应用程序将是所有发生的事情;中缀运算符总是以某些函数的参数结束,而实际上从未充当中缀运算符。

实际上,优先级(和关联性)是解决涉及多个中缀运算符的表达式含糊不清的机制。函数应用程序不是中缀运算符,并且不参与优先/关联系统。不涉及运营商的术语链被解析为函数应用,然后调用优先级来解析运营商应用(因此为“最高优先级”),但它不是真正的导致它的优先级。

这是它的工作原理。您从术语和运算符的线性序列开始;没有结构,它们只是简单地彼此相邻。

我称之为“术语”的可以是非运营商标识符,如flip;或字符串,字符或数字字面;或一个列表表达式;或括号的子表达式;等等。就这个过程而言,它们都是不透明的。我们只知道(而且只需要知道)他们不是中缀操作员。我们总是可以告诉操作员,因为它可以是“符号”标识符,如[email protected]>或反引号中的字母数字标识符。

所以,术语和操作符的顺序。您可以在一行中找到不包含任何运算符的所有链中的一个或多个术语。每个这样的链都是一系列功能应用程序,并成为一个单一的术语。

现在,如果您有两个直接相邻的操作员,则会出现错误。如果你的序列在一个操作符中开始或结束,那也是一个错误(除非这是一个操作符部分)。

在这一点上,你保证有一个严格的交替序列,如术语运算符术语运算符术语运算符术语等。因此,你选择最高优先级的运算符和左右两个术语,称之为运营商应用程序,这三个项目成为一个单一的术语。当多个运算符具有相同的优先级时,关联性可以作为平局休息。冲洗并重复,直到整个表达式变成一个单词(或关联性未能打破平局,这也是一个错误)。这意味着在涉及运营商的表达中,“顶级应用”是总是的运营商之一,绝不是普通的功能应用。

这样做的后果是存在无情况,在该情况下运算符可能最终作为参数传递给函数。这根本不可能。这就是为什么我们需要使用(:)语法来禁用运算符的“运算符”,并将其身份作为值来使用。

对于flip :非运算符术语的唯一链只是flip,所以没有普通函数应用程序来解析“在最高优先级”。 :然后寻找它的左和右参数(但这是一个部分,所以没有正确的参数),并在其左侧找到flip

要使flip收到:作为参数而不是其他方式,您必须编写flip (:)(:)不是运算符(它在括号内,所以它没有关系),所以我们有一个没有运算符的两个项的链,所以通过将flip应用到(:)可以解决单个表达式。


来看待这个另一种方法是,你确定运营商,否则不分离方面的所有序列,并插入它们之间的“功能应用运营商”。这个“运算符”的优先级高于可能分配给其他运算符的优先级,并且是左联合的。然后,运算符解析逻辑将按照我所描述的方式自动处理函数应用程序。

+0

谢谢 - 我知道关于parens,只是忘了做它!运算符和函数应用的优先级解释是有帮助的。 – guthrie 2014-12-29 13:43:30

8

你想要做的是什么:

λ> :t (flip (:)) 
(flip (:)) :: [a] -> a -> [a] 

运营商在Haskell为中缀。所以当你做flip :它以中缀的方式操作,即flip被应用于:函数。通过明确地在flip (:)中加上圆括号,您会发现:应该应用于flip。您也可以使用flip中的反引号操作符来制作您已经尝试过的中缀。

+3

打破它可以帮助你看到一致性:'让利弊=(:)在翻转缺点的作品,'让利弊=:在翻转缺点是一个错误 – rampion 2014-12-27 20:48:30