Синтаксически необходимы четкие открытые и закрытые разделители?

Проводя аналогию между умными кавычками и языками программирования, мне пришло в голову, что разные символы для открытия и закрытия разделителей могут быть не нужны, а просто выбор в читаемости.

Например, аргументы в анонимные функции Rubys используют одинаковые каналы для открытия и закрытия. Haskell использует пробел с крайними предрассудками.

Я не спрашиваю, нужны ли разные типы разделителей - скобки для индексировщиков, фигурные скобки для блоков - но существуют ли сильные и сильные синтаксически сильные различные открытые и закрытые фигурные скобки (например, ( и )) на большинстве языков или просто предпочтение дизайнеров.

Ответ 1

Не синтаксически необходимо, но если открытые и закрытые разделители одинаковы, это затрудняет (или невозможно) вложение вещей. Приложение A представляет собой оболочку POSIX, где

var=`command`

заменил на

var=$(command)

именно потому, что код с идентичными ограничителями открытия и закрытия не вложен.

Ответ 2

Наличие отдельных разделителей допускает вложенность. Список параметров блока Ruby не поддерживает вложенность, поэтому использование одного и того же разделителя в порядке.

Ответ 3

В C и С++ оголенные фигурные скобки могут быть вложенными и открытыми вложенными лексическими областями:

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

Используйте одинаковые разделители, и это неоднозначно:

|
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, для одного).

Ответ 4

print |foo|bar||

Может означать либо:

print (foo(bar))

или

print (foo)bar()

Оба из них действительны для Haskell и имеют разные значения. Но вы спрашиваете, можно ли в принципе изменить язык, чтобы он не требовал этого?

Хорошо, что вы можете сделать нечитаемую вещь. Вместо применения функций с сопоставлением введите префикс, оператор с двумя аргументами для приложения, назовите его *. Тогда:

foo (bar (baz quux)) bax

может быть однозначно записано:

* * foo * bar * baz quux bax

Приложение и один символ константы достаточно, чтобы закодировать вычисление комбинатора, так что технически, нет, вам вообще не нужны скобки (машины Тьюринга также не нуждаются в круглых скобках).

Но вы не можете просто сгладить все круглые скобки в барах и сделать это однозначно.

Ответ 5

Unlambda является примером для языка без скобок, фигурных скобок и т.д. Они заменяются одним оператором (Backtick), который стоит для "применять". Аналогично, в Haskell вы можете написать a $ b c вместо a (b c). Таким образом, есть способы избежать разных разделителей.

Ответ 6

Глядя на это с точки зрения разработчика, пишущего компилятор, я считаю, что проще использовать разделители. Я не совсем понимаю, что вы подразумеваете под разными разделителями, но вы можете технически использовать все, что вам нравится, в качестве символов на вашем языке. Просто посмотрите этот язык здесь. Просто посмотрите, насколько проще разбирать оператор if, когда он имеет открывающие и закрывающие фигурные скобки:

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

в отличие от:

if true
    doSomething
    thenDoSomethingElse

Помимо табуляции, как еще мне показать, что я хочу, чтобы оба этих метода выполнялись как часть тела if. Скобки дают понять парсеру, что все это происходит вместе. Проблема с языками, которые делают это, - это "проблема с болтающимися остатками":

if true
    if someCondition
        doSomething
else 
    doSomethingElse

Лучше сделать ваш синтаксический анализатор достаточно умным, чтобы знать, как совместить этот оператор else. Я думаю, что явные разделители делают это проще.

Ответ 7

Как уже упоминалось, они не нужны. Существуют и другие способы указать, когда начинается/заканчивается блок. При этом различные разграничители открывания и закрытия предоставляют больше информации людям, читающим код по очень маленькому коду. Эта информация может не только помочь читателю понять, что делает код, но и то, что было предназначено для.

В качестве примера этого, многие стандарты кодирования требуют скобок вокруг одного оператора, если блоки в C.