具有两个相同优先级的二进制运算符的语言,左关联和右关联


11

是否有任何编程(或脚本)语言(或某些特定领域的语言)具有两个二进制运算符,opl并且opr具有相同的优先级(opl左关联和opr右关联)?

(我找不到这样的示例,但是我正在尝试编写一些足以解析这种奇怪情况的解析器)

如何解析x opl y opr zx opr y opl z形式的表达式?更一般地说,甚至还有更多的操作数?


4
如果很痛,请不要这样做。
CodesInChaos

1
在Haskell中,您可以使用自己的优先级定义自己的中缀运算符,在这种情况下会出错。如果有x <@ y @> z<@被左结合和@>为右结合,GHC给你“优先分析错误”:“不能混合‘ <@’[infixl 0]和‘ @>’[infixr 0]中相同的缀表达式”(其中I定义例如,这些操作符的级别为0)。
Antal Spector-Zabusky '16

@ AntalSpector-Zabusky:那将是一个很好的答案!
Basile Starynkevitch 2016年

@ AntalSpector-Zabusky:与Swift相同。我认为您实际上可以定义运算符,但是在表达式中,您必须使用具有相同优先级的所有左关联运算符或所有右关联运算符。因此,您可以使用x leftop y leftop z或x rightop y rightop z,但不能使用x leftop y rightop z。
gnasher729

@BasileStarynkevitch:如您所愿!既然你提到的“灵活解析器”,我包括一对夫妇有更多晦涩的语言非常灵活的解析器(曾想if_then_else_[1;2;3]在库中定义?)。
Antal Spector-Zabusky '16

Answers:


10

这是三种语言,可让您定义自己的运算符,它们执行两种不同的操作!Haskell和Coq都禁止使用这种恶作剧,但有所不同-而Agda则允许这种联想性的混合。


首先,在Haskell中,根本不允许这样做。 您可以定义自己的运算符,并为其选择优先级(从0到9)和关联性。 但是,Haskell报告不允许您混合关联性

具有相同优先级的连续的非括号运算符必须左右关联,以避免语法错误。[Haskell 2010报告,第 3]

因此,在GHC中,如果我们以相同的优先级(假设为0 infixl)定义左关联()运算符<@和右关联运算符@>,则求值x <@ y @> z会得出错误

优先级分析错误
    不能在同一后缀表达式中混合使用' <@'[ infixl 0]和' @>'[ infixr 0]

(实际上,您还可以将运算符声明为infix但不关联,例如==,这x == y == z是语法错误!)


另一方面,有依存类型的语言/定理证明者阿格达Agda)(诚​​然,它不是主流)。Agda具有我所知道的任何一种语言中最具延展性的语法,支持mixfix运算符:标准库包含该函数

if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A

当被调用时写

if b then t else f

下划线加注!我之所以这么说是因为这意味着它必须支持极其灵活的解析。当然,Agda也具有固定性声明(尽管其优先级范围可以覆盖任意自然数,并且通常在0-100之间),并且Agda 确实允许您混合具有相同优先级但固定性不同的运算符。但是,我在文档中找不到有关此信息,因此我不得不进行实验。

让我们再利用<@@>从上面。在两种简单的情况下,

  • x <@ y @> z解析为x <@ (y @> z); 和
  • x @> y <@ z解析为(x @> y) <@ z

认为 Agda所做的就是将行分为“左关联”和“右关联”块,并且-除非我考虑不对,否则,右关联块在获取相邻参数时会获得“优先权”。这样就给了我们

a <@ b <@ c @> d @> e @> f <@ g

解析为

(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g

要么

解析<code>(((a <@ b)<@(c @>(d </ code> @>(e @> f)))的树))

但是,尽管进行了实验,但我还是第一次写错了,这可能是有启发性的:-)

(而且,像Haskell一样,Agda具有非关联运算符,它们可以正确给出解析错误,因此混合关联也可能导致解析错误。)


最后,有定理/依赖类型的语言Coq,其语法比Agda还要灵活,因为它的语法扩展实际上是通过为新语法结构提供规范,然后将其重写为核心语言来实现的(模糊地类似于宏) , 我想)。在Coq中,列表语法[1; 2; 3]是来自标准库的可选导入。新语法甚至可以绑定变量!

再一次,在Coq中,我们可以定义我们自己的中缀运算符,并为其赋予优先级(大多数情况下为0-99)和关联性。但是,在Coq中,每个优先级只能具有一个关联性。因此,如果我们定义<@为左关联,然后尝试@>在同一级别(例如50)下定义为右关联,我们得到

错误:级别50已被声明为左侧关联,而现在预计为右侧关联

Coq中的大多数运算符处于可以被10整除的级别上。如果我遇到了关联性问题(这些级别的关联性是全球性的),我通常只会在任一方向(通常是向上)将级别提高一个。


2
(Gee,语言的选择很奇怪。您能告诉我学习编程语言理论吗?:
P

非常感谢您的详细回答。顺便说一句,您如何绘制图片(使用哪种工具graphviz??)
Basile Starynkevitch

顺便说一句,为什么“固定性”而不是“优先性”?
Basile Starynkevitch

@BasileStarynkevitch:这取决于您的意思。如果您是在Coq部分中说的话,那只是一个错误:-)(现在已经解决了!)
Antal Spector-Zabusky

1
@BasileStarynkevitch:另外,我想念您关于图片的问题!我使用LaTeX软件包qtree进行了绘制,并在LaTeXit(用于Mac的LaTeX片段渲染器)中进行了渲染。相关的源代码为\ttfamily \Tree[.<@ [.<@ [.<@ a b ] [.@> c [.@> d [.@> e f ]]]] g ]
Antal Spector-Zabusky

2

自从它们由Douglas Crockford推广以来,Pratt解析器(或自上而下的运算符优先级解析器)已开始变得越来越普遍。这些解析器使用运算符优先级和关联性表工作,而不是将规则内置到固定的语法中,因此它们对于允​​许用户定义自己的运算符的语言很有用。

它们具有解析功能,该功能首先通过解析表达式的最左边的项,然后递归地绑定新的运算符和右手项,只要它们适当地绑定即可。左关联运算符将绑定优先级最高且包括相同优先级的右手术语,而右关联运算符仅绑定最高优先级,但不包括其优先级。我相信这会导致与上面引用的Agda相同的解析树。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.