Почему управляющие структуры Паскаля кажутся противоречивыми? - PullRequest
7 голосов
/ 07 января 2011

Большинство управляющих структур Паскаля имеют для меня смысл, как:

for ... do {statement};

if (condition) then {statement};

while (condition) do {statement};

где {оператор} является либо отдельным оператором, либо блоком begin ... end . У меня проблема с:

repeat {statement-list} until (expression);

try {statement-list} except {statement-list} end;

Не лучше ли, чтобы repeat и try имели одинаковую общую структуру, принимая только одно утверждение или begin ... end блок, вместо того, чтобы иметь список операторов, который формально не блокируется с begin и end ?

Ответы [ 7 ]

9 голосов
/ 07 января 2011

Формы, которые требуют начала / конца, существуют в одной строке - у компилятора нет другого способа узнать, где заканчивается блок.Формы, которые не требуют начала / конца, имеют закрывающую структуру, которая сообщает компилятору, где он заканчивается, и, таким образом, начало / конец будет просто избыточным.Вы можете использовать его в этом случае, если хотите.

8 голосов
/ 07 января 2011

Никлаус Вирт (дизайнер Паскаля) исправил эти несоответствия в своем следующем языке, Модула-2 . В Modula-2 составные операторы, такие как IF, не имеют BEGIN и обязательные END:

IF {condition} THEN
    {statement-list}
END;

Другие управляющие структуры, такие как WHILE, аналогичны и согласуются с REPEAT.

5 голосов
/ 07 января 2011

Вопрос: не лучше ли?

Ответ: это зависит от того, что такого рода вещи полностью субъективны. Если вы не являетесь или не думаете, что машина.

Да, для обеспечения согласованности принудительно вводить начало / конец для ВСЕХ составных выражений было бы достаточно, но если окружающие языковые элементы уже обеспечивают естественное вложение, требовать этого крайне избыточно.

Рассмотрим оператор CASE:

// "Sensible" syntax

  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    DoForAllOtherValues;
    DoMore;
  end;

По сравнению с менее разумным, но более последовательным и "логичным":

  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    begin
      DoForAllOtherValues;
      DoMore;
    end;
  end;

Обратите внимание, что последний "конец" является частью "дела". Без этого не обойтись.

Я вполне уверен, что в ранней версии Chrome (которая стала Oxygene, а затем Prism) это фактически требовал синтаксиса для оператора case. Если так, то это уже не так. Предположительно здравый смысл возобладал.

По моему личному мнению, удовлетворение OGoSC (Объективных Богов Синтаксической Последовательности) злит, возможно, меньшее, но на самом деле более актуальное для вас и меня, SGoHRaC (Субъективные Боги Человеческой Читаемости и Понимания).

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

Как и в этом случае.

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

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

Фактически, эти «более простые», более «согласованные» правила могут фактически усложнить все вокруг ... рассмотрим еще раз оператор CASE.

Для того чтобы это соединение начало / конец имело смысл, мы должны сделать "case" отдельным оператором, а не частью пары case / end, поэтому ВСЕ из них должны иметь правильный синтаксис:

  case VALUE of
    1: DoSomething;
    2: DoSomethingElse;


  case VALUE of
    1: DoSomething;
    2: DoSomethingElse;
  else
    DoOther;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    DoOther;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
  begin
    DoOther;
    DoMoreOther;
  end;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;

Вы можете не согласиться, но мне кажется, что внезапно этот более согласованный синтаксис фактически приводит к LESS-согласованности в реальном коде, даже при том, что в правилах, которым код написан для соответствия, существует большая согласованность.

3 голосов
/ 07 января 2011

Возможно. Но языковой дизайн, особенно языки с небольшой историей, редко бывает простым или идеальным.

Подобные вещи можно увидеть на других языках. Java, например, требует блок после try и не допускает ни одного оператора, хотя один оператор может также работать, если вы просто посмотрите на другие управляющие структуры.

Почему switch в C и производных языках является единым блоком, а отдельные случаи - нет?

2 голосов
/ 07 января 2011

Это связано с тем, как работает парсер. Начните / закончите, попробуйте / исключить и повторяйте / пока все не будут содержать блоки операторов. Код синтаксического анализатора выглядит примерно так: для блока начала (псевдокод):

procedure ReadBlock;
begin
  Match('begin');
  while CurrentToken <> 'end' do
    ReadStatement;
  Match('end');
end;

И это прекрасно работает для этого типа блока. Но когда вам нужна дополнительная информация в конечной строке блока (условие для повторения / до и блок обработки исключений для попытки), вы не захотите запускать ее до end , что грамматика языка предполагает, что после нее ничего не будет. Вы можете изменить грамматику, но это добавит много сложностей парсеру. Поэтому вместо этого вы просто выбираете другое ключевое слово.

1 голос
/ 04 февраля 2011

Вы частично правы - в утверждении repeat <stmts> until <expr>.

Чувствуется, что вам не хватает BEGIN-END для непротиворечивости составных выражений, но это позволяет избежать ненужных страданий.Поскольку вы видите, что во всех других случаях вам нужен эффект брекетинга начала и конца, чтобы показать, к какой части кода, к которой относится then или else или циклы do.REPEAT-UNTIL является единственным оператором Pascal, о котором я могу подумать, что это требует удаленной второй части - потому что имеет смысл условие для выхода из цикла в текстовом формате, где он будет проверяться - после тела цикла.Альтернативная форма могла бы быть

UNTIL <condition> DO <statement>

UNTIL <condition> DO
  BEGIN
    <statements>
  END

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

Что касается try <stmts> except <stmts> end - это не из оригинального дизайна и спецификации языка Pascal, это было добавлено в качестве запоздалой мысли некоторых разработчиков(Borland? FreePascal?), Так что неудивительно, что это противоречиво - мысль была скорее о том, «могу ли я сделать это, не ломая существующие программы», чем о полной спецификации проекта.Другой пример расширения языка был дан в ответе выше - пункт по умолчанию else в переключателе case - и хотя я нахожу это очень полезным и использовал его еще в те дни в Turbo Pascal - это ужасно несовместимо с использованиемelse в конструкции if.Таким образом, я нахожу другую реализацию, которую я видел и использовал лучше - otherwise:, за которой следует одно утверждение, как в каждом <value>: случае.

1 голос
/ 07 января 2011

Полагаю, вы задаете не тот вопрос. Я имею в виду, может быть, вы не видите разницы между группой if / while / for и группой повторов / попыток.

Первой группе нужно что-то (условие или аргументы), чтобы НАЧАТЬ что-то. Второе, напротив, предполагает НАЧАТЬ что-то. Просто прочитайте слова: повторите (следующее) и попробуйте (следующее).

Паскаль чистый, простой и элегантный, потому что он предназначен для постоянных читателей-людей. Профессор Вирт задумал людей, изучающих программирование, когда он разрабатывал его.

...