为什么 Haskell 优先级只有 10 级? 10这个数字够吗?

发布于 2024-11-15 07:16:46 字数 48 浏览 2 评论 0原文

我想知道为什么 Haskell 设计者同意只允许 10 级优先级?有人觉得不够吗?

I want to know why Haskell designers agreed to allow only 10 levels of precedence? Has anybody found it insufficient ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无戏配角 2024-11-22 07:16:46

据我所知,这完全是任意的。我所知道的所有文档都只是将其陈述为事实,没有详细说明或理由。

但如果你想一想,为什么还有其他更好的事情呢?好吧,假设 10 个还不够。您已经有了具有最高固定性的 (.),并且您想要其他绑定更紧密的东西。您添加了一个额外的级别,因此新的最大值为 10(尽管大多数固定性仅达到 9)。

现在您有 11 个优先级。 (这太荒谬了。一点都不好笑。)这怎么比 10 更不随意呢?是什么阻止您添加更多内容?如果您想在现有关卡之间添加新关卡怎么办?当然,您可以继续添加更多内容,直到最终您发现自己正在编写 infix↑ (ω + 2i) 并想知道您的生活出了什么问题。

问题是,运算符优先级本质上是一个相当任意的事情。有一些约定 - 乘法事物比加法事物绑定更紧密,逻辑运算符的优先级低于 (==) 等布尔值函数 - 但这些约定有些有限,通常不会涵盖多个级别。否则,记住运算符优先级的唯一方法是......好吧,记住它们,就像简单地记住每一个一样。这不仅是一件苦差事,而且还可能使代码对于其他可能没有记住所有内容的人来说不透明。人类工作记忆是一种非常有限的资源,因此在编码时需要回忆的挑剔细节越少越好。

Haskell 中优先级重要的运算符的大多数使用都属于以下几个粗略组之一:

  • 伪语法运算符,例如 ($) 的常见用法,通常需要极高或极低的优先级以避免与其他运算符。

  • 使用标准运算符或其变体的表达式,其中存在一些标准优先级,并且新运算符通常应与它们所基于的任何内容共享相同的级别。

    使用

  • 专用运算符集,例如 EDSL,其符号和优先级通常选择为反映 EDSL 的性质,并且不太可能与其他运算符集共存。

所有这些都可以很好地管理,只有几个优先级。更重要的是,它们的特点是要么有效地独立于其他运算符,要么仅与非常有限的其他运算符一起使用。开始添加更多运算符并将它们混合在单个表达式中,很快人们就会开始使用显式括号,因为他们不记得什么比什么绑定更紧密。就我自己而言,当我将 EDSL 风格的运算符(例如,Arrow 组合器)与逻辑运算符混合时,我已经很容易使用显式括号,因为我通常无法回忆起每个运算符具有的确切优先级。

因此,确定:1)许多额外的优先级不会那么有用,因为它太多而难以跟踪,并且2)我们选择的任何限制都是同样任意……为什么是 10?我会猜测“因为这样固定值只是个位数”。

To the best of my knowledge, it's completely arbitrary. All the documentation I'm aware of simply states it as a point of fact, with no elaboration or justification.

But if you think about it, why would anything else be better? Okay, let's say 10 isn't enough. You've got (.) which has the highest fixity and you want something else that binds a bit tighter. You add an extra level, so your new maximum is 10 (even though most fixities only go to 9).

Now you have 11 levels of precedence. (That's ridiculous. It's not even funny.) How is this any less arbitrary than 10? What's to stop you from adding more? What if you want new levels between existing ones? Sure, you can keep adding more, until eventually you find yourself writing infix↑ (ω + 2i) and wondering where your life went wrong.

The thing is, operator precedence is inherently a pretty arbitrary thing. There are a few conventions--multiplicative things binding tighter than additive ones, logical operators having lower precedence than boolean-valued functions like (==)--but those are somewhat limited, and usually don't cover more than a few levels. Otherwise, the only way to remember operator precedences is to... well, remember them, as in simply memorize each one. Not only is this a chore, it can make code opaque to others who may not have everything memorized as well. Human working memory is a very limited resource, so the fewer picky details that need to be recalled while coding, the better.

Most uses of operators in Haskell where precedence matters fall into one of several rough groups:

  • Pseudosyntactic operators like the common use of ($), which typically need extremely high or low precedence to avoid conflicting with other operators.

  • Expressions using standard operators, or variations thereof, where a handful of standard precedence levels exist and new operators should generally share the same level as whatever they're based on.

  • Specialized operator sets, such as for an EDSL, whose symbols and precedence levels are typically chosen to reflect the nature of the EDSL and are unlikely to coexist with other sets of operators.

All of those manage just fine with only a few precedence levels. More importantly, they're characterized by either being effectively independent of other operators or only used together with a very limited set of other operators. Start adding in more operators and mixing them together in single expressions and pretty soon people will start using explicit parentheses anyway because they can't remember what binds more tightly than what. Speaking for myself, I'm already prone to explicit parenthesization when mixing EDSL-style operators (say, Arrow combinators) with logical operators because I can't usually recall the exact precedence levels each one has.

So, having established that: 1) lots of extra precedence levels wouldn't be that useful because it's too much to keep track of, and 2) any limit we pick is going to be equally arbitrary... why 10? I'm going to guess "because then fixity values are only single digits".

辞慾 2024-11-22 07:16:46

级别的数量是任意的,而且我记得决定是很多级别只会让人很难记住操作员如何交互。例如,Prolog 允许 1000 个级别,但我从未发现它比 Haskell 好得多。

扩展 Haskell 优先级级别您可以想象更改为有理数,这样您始终可以在两个现有运算符之间安装一个运算符。但更好的选择可能是切换到部分顺序的优先级。因此,给定两个运算符,它们可以相关,然后进行相应处理,或者不相关,这将强制使用括号。

The number of levels is arbitrary, and as I recall the decision was that lots of levels just makes it hard to remember how the operators interact. For instance Prolog allows 1000 levels, but I've never found that to be much better than Haskell.

Extending Haskell precedences levels you could imagine changing to a rational number, that way you can always fit an operator between two existing operator. But a better choice would probably be to switch to the precedences being a partial order. So given two operators they can be related and then handled accordingly, or unrelated which would force parenthesis.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文