在语法上有必要使用不同的打开和关闭分隔符

本文关键字:分隔符 语法 | 更新日期: 2023-09-27 18:00:45

在对智能引号和编程语言进行类比时,我突然想到,用于打开和关闭分隔符的不同字符可能没有必要,而只是可读性方面的一种选择。

例如,Ruby的匿名函数中的参数使用相同的管道来打开和关闭。哈斯克尔在使用白色空间时带有极端的偏见。

我不是在问是否需要不同的分隔符类型——括号用于索引器,大括号用于块——而是在大多数语言中,不同的开括号和闭括号(例如())在语法上是否是所必需的,或者只是设计者的偏好。

在语法上有必要使用不同的打开和关闭分隔符

语法上没有必要,但如果打开和关闭分隔符相同,则会使嵌套变得困难(或不可能)。证据A是POSIX外壳,其中

var=`command`

已替换为

var=$(command)

正是因为具有相同的开头和结尾分隔符的代码没有嵌套

具有不同的分隔符允许嵌套。Ruby的块参数列表不支持嵌套,所以可以使用相同的分隔符。

在C和C++中,可以嵌套裸大括号,并打开嵌套的词法作用域:

{
    int a = 42;
    {
        int a = 24;
        {
            printf("%d'n", a); // prints 24
        }
    }
}

使用相同的delimeter,这是不明确的:

|
int a = 42;
|
int a = 24;
| // Is this an open or close pipe?
printf("%d'n", a); // 24? 42?
| // could be a pair
| // of open+close
|

考虑到C语法规则的普遍性,可能还有许多其他语言存在类似的问题(例如perl)。

print |foo|bar||

可能意味着:

print (foo(bar))

print (foo)bar()

这两者都是有效的Haskell,具有不同的含义。但你在问,原则上是否可以调整语言以不要求这样做?

你可以做一件不可读的事情。与其应用并置函数,不如为应用程序引入一个前缀2-参数运算符,称之为*。然后:

foo (bar (baz quux)) bax

可以毫不含糊地写:

* * foo * bar * baz quux bax

应用程序和一个常量符号就足以编码组合子微积分,所以,在技术上,不,你根本不需要括号(图灵机也不需要括号)。

但你不能只是把所有的括号都熨成条形,然后让它明确地有意义。

Unlambda是一个没有括号、大括号等的语言的例子。它们被一个表示"应用"的运算符(Backtick)取代。类似地,在Haskell中,您可以编写a $ b c而不是a (b c)。因此,有一些方法可以避免使用不同的分隔符。

从编写编译器的开发人员的角度来看,我认为使用分隔符更容易。我不确定你所说的不同的分隔符到底是什么意思,但从技术上讲,你可以在语言中使用任何你喜欢的符号。看看这里的语言。只要看看当if语句有左大括号和右大括号时解析它有多容易:

if (true)
{
    doSomething();
    thenDoSomethingElse();
}

与相反

if true
    doSomething
    thenDoSomethingElse

除了选项卡之外,我还应该如何表明我希望这两个方法都作为if主体的一部分执行。大括号让解析器清楚地知道,所有这些都是一起进行的。这样做的语言的问题是"悬挂的其他问题":

if true
    if someCondition
        doSomething
else 
    doSomethingElse

你最好让你的解析器足够聪明,知道如何匹配else语句。我认为明确的分隔符使这更容易。

正如其他人所提到的,它们不是必需的。还有其他方式可以指示块何时开始/结束。也就是说,不同的打开和关闭分隔符为阅读代码的人提供了更多的信息。这些信息不仅可以帮助读者了解代码在做什么,还可以它打算做什么

例如,许多编码标准要求在C.中的单个语句if块周围使用大括号