我们需要谈谈括号(2020)
围绕编程语言在多大程度上应依赖括号和运算符优先级的争论,揭示了可读性、熟悉度与元编程能力之间的深层权衡。一些参与者主张尽量减少优先级规则、更多显式分组(甚至采用 RPN 风格语法),而另一些人则为传统的类数学规则和 Lisp 那种完全括号化的 S 表达式辩护,尤其是在配合良好的缩进和编辑器支持时。讨论还涉及语法如何影响工具、作用域以及代码转换的便利性,以及为什么尽管 Lisp 具有宏和“代码即数据”的优势,大多数主流语言仍然倾向于更丰富、也更不统一的语法形式。
运算符优先级 vs. 强制括号
- 一派认为运算符优先级是一个设计错误;像
1 + 1 * 2或a | b || c >> d & e * f这样的混合运算表达式,除非显式加括号,否则都应该是语法错误。 - 另一派强烈反对,理由包括记号更简洁、与代数类比,以及过度加括号代码带来的负担。
- 提议的折中方案是:采用一种 部分 优先级顺序。常见组合(例如
*高于+)允许;不常见的混合(例如*与&)则以“优先级歧义”为由拒绝。 - 争论还延伸到数学:有人认为优先级是内在的(“运算顺序”);也有人坚持它纯粹是记号的属性,往往通过分数、上标、根号等视觉方式来表达。
Lisp 括号、可读性与工具
- 许多人指出,在 Lisp 中,自动缩进、结构化编辑和括号高亮被视为必不可少;这些工具能迅速暴露缺失或放错位置的括号。
- 有人认为 Lisp 只有一种括号会损害可读性,并建议为不同的语法角色使用多种括号类型,甚至让不同括号仅用于视觉分组、彼此可互换。
- 反方观点是:有经验的 Lisp 用户更多是“看形式”,而不是看括号,他们依赖以符号开头的模式,而不是数括号。
- 结构化编辑受到赞扬:显式分隔符加自动格式化,像代码结构的“复式记账”。
语法风格、空白与作用域
- 有人称赞那些在
if条件等结构中去掉不必要括号的语言(Go、Scala 3)。 - 对显著空白也存在分歧:有些人偏好显式分隔符;另一些人则觉得以缩进为中心的语法更易读。
- 讨论还涉及作用域:紧凑的词法块(
{}或let形式)可以减少活动变量,但并非所有生命周期都能被最小化;C、Rust(非词法生命周期)以及函数式/单子代码中的例子都说明了这些权衡。
Lisp 的代码即数据与元编程
- 一些评论强调,Lisp 的括号表示的是列表;程序就是列表,而引用则把代码变成数据。
- 简单的列表操作就能转换代码(例如把所有
*替换成+然后eval),这为强大的宏和领域特定语法提供了基础。 - 支持者认为这是 Lisp 的核心优势;怀疑者则回应说,如今其他语言也提供了强大的元编程能力,同时视觉上不那么重复,并质疑括号是否真的是更好的人体工学折中。