Даю разгадку про Алгол-68 и Bash. В них не нужен цикл с постусловием, поскольку 
в них внутри выражения можно писать оператор (кстати, эта идея заимствуется 
многими современными языками программирования, например, Rust и Cotlin).

Bash, цикл с предусловием:

while
  prog1
do
  prog2
  prog3
od

Bash, цикл с выходом посередине:

while
  prog1
  prog2
do
  prog3
od

Bash, цикл с выходом посередине и пустым телом == цикл с постусловием:

while
  prog1
  prog2
  prog3
do
  :
od

Этот цикл будет продолжаться, пока программа prog3 будет выдавать нулевой, 
успешный код возврата. И цепочка prog1; prog2; prog3 выполнится хотя бы один 
раз. Цикл с постусловием. (Двоеточие в Bash — специальное обозначение пустой 
команды, которая всегда выполняется успешно.)

> void sift(T a[], unsigned n, unsigned p) {
>   unsigned j;
>   T x = a[p];
>   for (;;) {
>     if (j=2*p+1, j+1<n && a[j]<a[j+1])  ++j;
>     if (j>=n || a[j]<=x)  break;
>     a[p] = a[j];  p = j;
>   }
>   a[p] = x;
> }

Алгол-68 (не исключаю мелкие ошибки в синтаксисе):

proc sift = (ref [] T a, int n, int p) void: (
  int j;
  T x := a[p];
  while (
    if (j := 2*p + 1; j + 1 < n) and a[j] < a[j + 1] then  j +:= 1;
    j < n and a[j] > x
  ) do
    a[p] := a[j]; p := j
  od;
  a[p] := x
)

Красота. И никаких break’ов и goto. Структурное программирование :-).


Книжка про Симулу следующая:
Андрианов А. Н., Бычков С. П., Хорошилов А. И. Программирование на языке 
симула-67.— М.: Наука. Глав. ред. физ.-мат. лит., 1985.— 288 с.

Процитирую один фрагмент из книги, интересный в контексте рассылки 
refal@botik.ru:

Стр. 8:
«Авторы считают приятным долгом выразить благодарность … А. А. Веденову, С. А. 
Романенко, А. Е. Фирсову за помощь в использовании рефал-систем на БЭСМ-6 и ЕС 
ЭВМ …» 

И ещё, стр. 169:
«При реализации широко применялся язык рефал [5], ориентированный на 
программирование сложных символьных преобразований. Наличие на машинах БЭСМ-6 и 
ЕС ЭВМ реализаций рефала [5, 14], практически полностью совместимых по входному 
языку, позволило значительно сократить трудоёмкость разработки 
симула-компиляторов, особенно компилятора для ЕС ЭВМ, основу которого составили 
программы ранее разработанного транслятора с языка симула-67 для БЭСМ-6.»

Ссылки списка литературы (см. выше):
«5. Базисный РЕФАЛ. Описание языка и основные приемы программирования 
(методические рекомендации). Вып. V-33.— М.: ЦНИПИАСС, 1974.— 95 с.
…
14. Климов Ан. В., Романенко С. А. Рефал в мониторной системе Дубна. Интерфейс 
рефала и фортрана.— М., 1975.— 34 с. (Препринт/ИПМ им. М. В. Келдыша АН СССР)»

-----Original Message-----
From: Boyko Bantchev [mailto:boyk...@gmail.com] 
Sent: Thursday, August 10, 2017 12:45 AM
To: refal@botik.ru
Subject: Re: FW: Рефал умер?

> был очень витиеватый цикл for, который мог быть даже while

Вот именно: while-ом можешь ты и быть, но for-ом все равно быть обязан.
Хочешь не хочешь, а for и «управляющая переменная» обязательны для цикла.  Даже 
когда переменная никак не нужна и нигде не используется.
Поэтому написал, что оператор цикла в Алголе-60 единственный.

А в Алголе-68 не так: там никакая часть не обязательна.  Можно счетчик 
использовать, можно и условие, но все на выбор.

(Еще более это развито в ПЛ/1 — в нем голова кружится от возможностей написать 
цикл, как впрочем и почти все остальное.  Цикл ПЛ/1 скопирован в REXX, который 
и ныне здравствует.)

> Впрочем, и польза от разумной структурности тоже вполне обоснована

Конечно, это само собой, никто не спорит.
Проблема в том, что принято только пользу подчеркивать, а о вреде умалкивают.  
Ниже приведу пример в этом духе.

> Читал как-то отечественную книжку 80-х годов про Симулу-67. Редкий 
> метод в ней обходился без goto

Если и была такая книжка, не думаю что она показательна в данном отношении.  
Книг по программированию на русском у меня много, а покупал их как раз в это 
время.  (Тогда у нас их продавали в большом количестве, очень недорого, и у 
меня накопилась библиотека приличного
размера.)  Но злоупотребление goto нигде не встречал.

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

> … в конце 70-х Владимир Леонидович Топунов учил что, если предполагаемый 
> эффект от оптимизации меньше 10%, то не следует даже браться...

Роджер Хюи, автор (совместно с К.Айверсоном) и главный реализатор языка J 
(наследника APL) утверждает, что никакую оптимизацию не стоит делать, если 
приведет к улучшению не больше чем в два раза!

Но!  Под оптимизацией можно понимать разные вещи.  Меня в этой дискуссии 
мотивирует не оптимизация в смысле повышения быстродействия, а экономия.  Не 
вводить лишнее, не повторять действия, расставить нужное где ему лучше быть.  
Организовать программу из таких соображений, а не из соображений придерживания 
к неясно чем полезным на практике правилам.

Приведу пример: процедура проталкивания в пирамиду.  У меня она получается так:

void sift(T a[], unsigned n, unsigned p) {
  unsigned j;
  T x = a[p];
  for (;;) {
    if (j=2*p+1, j+1<n && a[j]<a[j+1])  ++j;
    if (j>=n || a[j]<=x)  break;
    a[p] = a[j];  p = j;
  }
  a[p] = x;
}

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

А это вариант Н.Вирта из его известной книги — текст то ли на Модуле, то ли на 
Обероне:

PROCEDURE sift(L, R: INTEGER);
  VAR i, j: INTEGER; x: Item;
BEGIN i := L; j := 2*i+1; x := a[i];
  IF (j < R) & (a[j] < a[j+1]) THEN j := j+1 END;
  WHILE (j <= R) & (x < a[j]) DO
    a[i] := a[j]; i := j; j := 2*j+1;
    IF (j < R) & (a[j] < a[j+1]) THEN j := j+1 END
  END;
  a[i] := x
END sift;

Есть различия несущественные, но главная в моем понимании проблема здесь — 
дублирование строк 4 и 7, только из желания избежать выхода из тела цикла, быть 
«структурным».  Не знаю чем это может быть полезным, для меня оно выглядит 
нелепо.  Хоть и из уст великих.
В самом первом варианте книги (на Паскале) Вирт использовал goto для выхода из 
цикла и дублирования действий нет.  Потом «эволюировал».

Ответить