这是三种语言,可让您定义自己的运算符,它们执行两种不同的操作!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
要么
但是,尽管进行了实验,但我还是第一次写错了,这可能是有启发性的:-)
(而且,像Haskell一样,Agda具有非关联运算符,它们可以正确给出解析错误,因此混合关联也可能导致解析错误。)
最后,有定理/依赖类型的语言Coq,其语法比Agda还要灵活,因为它的语法扩展实际上是通过为新语法结构提供规范,然后将其重写为核心语言来实现的(模糊地类似于宏) , 我想)。在Coq中,列表语法[1; 2; 3]
是来自标准库的可选导入。新语法甚至可以绑定变量!
再一次,在Coq中,我们可以定义我们自己的中缀运算符,并为其赋予优先级(大多数情况下为0-99)和关联性。但是,在Coq中,每个优先级只能具有一个关联性。因此,如果我们定义<@
为左关联,然后尝试@>
在同一级别(例如50)下定义为右关联,我们得到
错误:级别50已被声明为左侧关联,而现在预计为右侧关联
Coq中的大多数运算符处于可以被10整除的级别上。如果我遇到了关联性问题(这些级别的关联性是全球性的),我通常只会在任一方向(通常是向上)将级别提高一个。