Re: FW: Рефал умер?

2017-08-10 Пенетрантность Boyko Bantchev
> Т.е. исходный алгоритм на Си на пару писем раньше тоже был запутанным

Спасибо, Александр!  Подтверждаю.  Во всем виноват я.  Написал очень
запутанную процедуру.  Допишу имейл и предприму самобичевание плетью
с крючками.

> А все-таки на следующей странице оно понятнее (функция siftDown)

Конечно!  Удваивание количества используемых переменных, выход из
двух мест вместо одного и многократное подталкивание значения мелкимми
шажками (вместо того, чтобы найти его место и поставить раз) – все это
чрезвычайно способствует ясности.

> А чтобы добиться структурности вам приходится ...

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

> Да к тому же обеспечить доступ в теле цикла к вычисленному внутри условий 
> индексу j, объявив j вне цикла.

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

> Стало, конечно, структурно, но более запутанно.

Как уже сказал, что такое «структурно» и чем оно полезно я понятия не
имею.  А насчет «запутанно» я уже согласился устами и обеими руками.

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

if (j=2*p+1, j+1=n || a[j]<=x)  break;
Если наследник за пределом массива или он мал, выходим из цикла.

a[p] = a[j];  p = j;
Поднимаем к себе наследника.  Занимаем его место.


RE: FW: Рефал умер?

2017-08-10 Пенетрантность Александр Коновалов
Согласен, там понятнее. Я просто хотел проиллюстрировать, что в Алголе-68 есть 
синтаксис для цикла, условие которого проверяется в середине. И для этого 
_дословно_ переписал алгоритм, предложенный Бойко на Си (у него был бесконечный 
цикл с единственным выходом по break в середине). Т.е. исходный алгоритм на Си 
на пару писем раньше тоже был запутанным.

 

From: Arkady Klimov [mailto:arkady.kli...@gmail.com] 
Sent: Thursday, August 10, 2017 8:42 PM
To: refal@botik.ru
Subject: Re: FW: Рефал умер?

 

А все-таки на следующей странице оно понятнее (функция siftDown):

 

https://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0

 

Фишка в том, что для выхода из цикла while здесь имеются две разные причины: 

1) у данной текущей вершины p (там i) нет потомков (2*p+1>=n) или 

2) потомки есть (один или два), но все они (в частности, больший, который 
обозначен через j) имеют значение a меньшее (или равное) текущей (x, там a[i]). 
И потому для второго выхода там используется break, т.е. неструктурность.

А чтобы добиться структурности вам приходится эти два условия соединить в одно 
через "или" и тут же в скобках под while вписать все что надо для их 
вычисления. Да к тому же обеспечить доступ в теле цикла к вычисленному внутри 
условий индексу j, объявив j вне цикла. Стало, конечно, структурно, но более 
запутанно.

 

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

 

 

10 августа 2017 г., 16:14 пользователь Александр Коновалов 
mailto:a.v.konovalo...@mail.ru> > написал:

> А мой вариант на Си не структурный?  У него один вход и один выход.
> Что и есть по вашему определению структурность.  Или отреклись уже? :)

Формально выход один, так что по сформулированному мной определению, да, 
структурно.

> При этом у меня процедура вроде правильно работает.  А ваша на
> Алголе-68 ошибится индексированием — операция and в Алголе-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 | a[j] < a[j + 1] | false) then  j +:= 1;
(j < n| a[j] > x | false)
  ) do
a[p] := a[j]; p := j
  od;
  a[p] := x
)

Заодно понял, для чего нужна сокращённая запись if.

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

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

А мой вариант на Си не структурный?  У него один вход и один выход.
Что и есть по вашему определению структурность.  Или отреклись уже? :)

При этом у меня процедура вроде правильно работает.  А ваша на
Алголе-68 ошибится индексированием — операция and в Алголе-68 не ленивая :)





 

-- 

___

С уважением, 

Аркадий Климов,
с.н.с. ИППМ РАН,
+7(499)135-32-95
+7(916)072-81-48



Re: FW: Рефал умер?

2017-08-10 Пенетрантность Arkady Klimov
А все-таки на следующей странице оно понятнее (функция siftDown):

https://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0

Фишка в том, что для выхода из цикла while здесь имеются две разные
причины:
1) у данной текущей вершины p (там i) нет потомков (2*p+1>=n) или
2) потомки есть (один или два), но все они (в частности, больший, который
обозначен через j) имеют значение a меньшее (или равное) текущей (x, там
a[i]). И потому для второго выхода там используется break, т.е.
неструктурность.
А чтобы добиться структурности вам приходится эти два условия соединить в
одно через "или" и тут же в скобках под while вписать все что надо для их
вычисления. Да к тому же обеспечить доступ в теле цикла к вычисленному
внутри условий индексу j, объявив j вне цикла. Стало, конечно, структурно,
но более запутанно.

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


10 августа 2017 г., 16:14 пользователь Александр Коновалов <
a.v.konovalo...@mail.ru> написал:

> > А мой вариант на Си не структурный?  У него один вход и один выход.
> > Что и есть по вашему определению структурность.  Или отреклись уже? :)
>
> Формально выход один, так что по сформулированному мной определению, да,
> структурно.
>
> > При этом у меня процедура вроде правильно работает.  А ваша на
> > Алголе-68 ошибится индексированием — операция and в Алголе-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 | a[j] < a[j + 1] | false) then  j +:= 1;
> (j < n| a[j] > x | false)
>   ) do
> a[p] := a[j]; p := j
>   od;
>   a[p] := x
> )
>
> Заодно понял, для чего нужна сокращённая запись if.
>
> -Original Message-
> From: Boyko Bantchev [mailto:boyk...@gmail.com]
> Sent: Thursday, August 10, 2017 11:57 AM
> To: refal@botik.ru
> Subject: Re: FW: Рефал умер?
>
> > Красота. И никаких break’ов и goto. Структурное программирование :-)
>
> А мой вариант на Си не структурный?  У него один вход и один выход.
> Что и есть по вашему определению структурность.  Или отреклись уже? :)
>
> При этом у меня процедура вроде правильно работает.  А ваша на
> Алголе-68 ошибится индексированием — операция and в Алголе-68 не ленивая :)
>



-- 
___
*С уважением, *
*Аркадий Климов,*
*с.н.с. ИППМ РАН,*
*+7(499)135-32-95*
*+7(916)072-81-48*


RE: FW: Рефал умер?

2017-08-10 Пенетрантность Александр Коновалов
> А мой вариант на Си не структурный?  У него один вход и один выход.
> Что и есть по вашему определению структурность.  Или отреклись уже? :)

Формально выход один, так что по сформулированному мной определению, да, 
структурно.

> При этом у меня процедура вроде правильно работает.  А ваша на
> Алголе-68 ошибится индексированием — операция and в Алголе-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 | a[j] < a[j + 1] | false) then  j +:= 1;
(j < n| a[j] > x | false)
  ) do
a[p] := a[j]; p := j
  od;
  a[p] := x
)

Заодно понял, для чего нужна сокращённая запись if.

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

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

А мой вариант на Си не структурный?  У него один вход и один выход.
Что и есть по вашему определению структурность.  Или отреклись уже? :)

При этом у меня процедура вроде правильно работает.  А ваша на
Алголе-68 ошибится индексированием — операция and в Алголе-68 не ленивая :)


Re: FW: Рефал умер?

2017-08-10 Пенетрантность Boyko Bantchev
> Красота. И никаких break’ов и goto. Структурное программирование :-)

А мой вариант на Си не структурный?  У него один вход и один выход.
Что и есть по вашему определению структурность.  Или отреклись уже? :)

При этом у меня процедура вроде правильно работает.  А ваша на
Алголе-68 ошибится индексированием — операция and в Алголе-68 не
ленивая :)


RE: FW: Рефал умер?

2017-08-09 Пенетрантность Александр Коновалов
Даю разгадку про Алгол-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 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) утверждает, что никакую оптимизацию не стоит делать, если 
приведет к улучшению не больше чем в два раза!

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

Приведу пример: процедура проталкива

Re: FW: Рефал умер?

2017-08-09 Пенетрантность Boyko Bantchev
> был очень витиеватый цикл 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]<=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 для
выхода из цикла и дублирования действий нет.  Потом «эволюировал».


Re: FW: Рефал умер?

2017-08-09 Пенетрантность Boyko Bantchev
> bool goon = true;
> for (row=0; row < MAXROW && goon; ++row)
>   for (col=0; col < MAXCOL && goon; ++col)
> goon = elem_at(row,col) == 0;

Я только сейчас всмотрелся внимательнее в эту программку.
Сергей Абрамов правильно отметил, что goon вполне может
быть локальной во внешнем цикле.
Но есть проблемма посерьезнее: программа просто не формирует
правильный результат.

Избежание goto и break considered harmful ;)


RE: FW: Рефал умер?

2017-08-09 Пенетрантность Александр Коновалов
Добрый день, Сергей!

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

И это цитирует специалист по метавычислениям и суперкомпиляции — технологии 
оптимизации программ. :-)

-Original Message-
From: Sergei M. Abramov [mailto:ab...@botik.ru] 
Sent: Wednesday, August 9, 2017 5:07 PM
To: Boyko Bantchev ; refal@botik.ru
Subject: Re: FW: Рефал умер?

>> Плата за структурное программирование.  В варианте Сергея Абрамова (в 
>> следующем письме) вводится дополнительная булевская переменная и тоже 
>> требуется дополнительная проверка

> И, кроме того, дополнительная переменная оказывается нелокальной для 
> цикла,-ов, хотя ей лучше быть локальной, ведь дальше она не 
> используется.

Ну, это я так написал. Перетащите ее мышкой правее первого слова for и она 
станет локальной.

По поводу "дальше она не используется"... это зависит от задачи ;-) Ее смысл: 
уже нашли или еще нет.  То есть, это то самое <элемент
обнаружен>.  И в этом смысле, то, что я написал
НИКАК не отличается от:

> <установить на начало>
> while (! <достигли конца> && ! <элемент обнаружен>)
>   <вычисление следующего и переход к нему> if (<достигли конца>)
>   <действия, если элемент не найден>
> else
>   <действия, если элемент найден>

Считать, что вот такой переход в 2D-массиве:

>, ++col;
>  if (col == MAXCOL) {
>col = 0;
>++row;
>  }

лучше вложенного  цикла... Ну, не знаю ;-) Дело вкуса ;-) А о нем не спорят.

Мои предпочтения давно в области прозрачности кода для чтения, а не в области 
эффективности для исполнения.

Лет семь назад встретил цитаты из великих (не помню кто и цитата по памяти, не 
точный текст):

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

С тей пор как прочитал, как и отрезало ;-)

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

Всего доброго,

Сергей Абрамов



RE: FW: Рефал умер?

2017-08-09 Пенетрантность Александр Коновалов
твенную книжку 80-х годов про 
Симулу-67. Редкий метод в ней обходился без goto.)

-Original Message-
From: Boyko Bantchev [mailto:boyk...@gmail.com] 
Sent: Wednesday, August 9, 2017 1:58 PM
To: refal@botik.ru
Subject: Re: FW: Рефал умер?

Здравствуйте, Александр!

> Понравилась реализация необязательного параметра n в макросе

Спасибо.  Но этот прием не я придумал.  Видел где-то.

А вот полным решением проблемы с избыточностью имен в struct в Си я горжусь :) 
И в учебниках по программированию на Си, и в реальных программах — тонны этой 
избыточности, но решение показывает, что она не нужна.

> Мой пример выглядел бы так:
>
> int row, col;  // используются после цикла, нельзя объявлять внутри.
> loop (
>   row = 0; col = 0
> , row < MAXROW && elem_at(row, col) == 0 , ++col;
>   if (col == MAXCOL) {
> col = 0;
> ++row;
>   }
> )
>   // тело пустое, как я и предполагал
> fin();

Возможно, вы смотрели определение loop в статье?
То, что в файле m.cpp, является более поздним и с ним данный фрагмент
не сработает.   Ваш вариант поиска я записал бы так:

loop (row = 0; col = 0 , row < MAXROW)
exitif (elem_at(row, col) != 0)
upd (if (++col == MAXCOL) { col = 0; ++row;}) fin();

Преимущества:
   проверка нахождения нужного элемента выделена самостоятельно;
   искомое условие для элемента сформулировано положительно;
   тело цикла не пусто;
   обновление индексов лучше сосредоточено в одной конструкции.

> Фишка этого примера в том, что он записывается целиком в рамках структурного 
> программирования: без goto, break и return.

Это если принять, что в структурном программировании их нет.
Но данная точка зрения не единственная.

> Плата за структурное программирование. В варианте Сергея Абрамова (в 
> следующем письме) вводится дополнительная булевская переменная и тоже 
> требуется дополнительная проверка

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

Плата за структурное программирование?  Скорее, по-моему, это плата за 
определенное, очень конкретное понимание структурного программирования.  Но 
единого определения этого понятия, с которым все были бы согласны, нет.  Зачем 
подгонять решения задач под какое-то представление о структурности, которое 
даже не является общепризнанным?  Что получаем за «плату»?  Ведь решения 
становятся в той или иной мере искусственными (признаком чего является 
избыточность имен и действий), а что получаем навстречу и так ли оно ценно?  Не 
лучше ли пересмотреть наше понимание о структурности?

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

Признано, что придерживаться какого-нибудь множества структурных схем нужно, но 
по-моему так же нужно выбор этого множества время от времени пересматривать.  
Иначе в императивном программировании мы бы остались с Фортраном или 
Алголом-60, у каждого из которых имеется единственный оператор цикла.  А в 
функциональном программировании так и не пришли бы к лексическому связыванию, 
частичному применению, одноаргументности и композиции функций и сопоставлению с 
образцом — остались бы с Лиспом, у которого их и сегодня нет, за исключением 
лексического связывания.

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


Re: FW: Рефал умер?

2017-08-09 Пенетрантность Sergei M. Abramov
>> Плата за структурное программирование.  В варианте Сергея Абрамова
>> (в следующем письме) вводится дополнительная булевская переменная и
>> тоже требуется дополнительная проверка

> И, кроме того, дополнительная переменная оказывается нелокальной
> для цикла,-ов, хотя ей лучше быть локальной, ведь дальше она не
> используется.

Ну, это я так написал. Перетащите ее мышкой правее первого слова for и
она станет локальной.

По поводу "дальше она не используется"... это зависит от задачи ;-)
Ее смысл: уже нашли или еще нет.  То есть, это то самое <элемент
обнаружен>.  И в этом смысле, то, что я написал
НИКАК не отличается от:

> <установить на начало>
> while (! <достигли конца> && ! <элемент обнаружен>)
>   <вычисление следующего и переход к нему>
> if (<достигли конца>)
>   <действия, если элемент не найден>
> else
>   <действия, если элемент найден>

Считать, что вот такой переход в 2D-массиве:

>, ++col;
>  if (col == MAXCOL) {
>col = 0;
>++row;
>  }

лучше вложенного  цикла... Ну, не знаю ;-) Дело вкуса ;-) А о нем не
спорят.

Мои предпочтения давно в области прозрачности кода для чтения, а не в
области эффективности для исполнения.

Лет семь назад встретил цитаты из великих (не помню кто и цитата по
памяти, не точный текст):

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

С тей пор как прочитал, как и отрезало ;-)

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

Всего доброго,

Сергей Абрамов



Re: FW: Рефал умер?

2017-08-09 Пенетрантность Boyko Bantchev
Здравствуйте, Александр!

> Понравилась реализация необязательного параметра n в макросе

Спасибо.  Но этот прием не я придумал.  Видел где-то.

А вот полным решением проблемы с избыточностью имен в struct в Си
я горжусь :)
И в учебниках по программированию на Си, и в реальных программах —
тонны этой избыточности, но решение показывает, что она не нужна.

> Мой пример выглядел бы так:
>
> int row, col;  // используются после цикла, нельзя объявлять внутри.
> loop (
>   row = 0; col = 0
> , row < MAXROW && elem_at(row, col) == 0
> , ++col;
>   if (col == MAXCOL) {
> col = 0;
> ++row;
>   }
> )
>   // тело пустое, как я и предполагал
> fin();

Возможно, вы смотрели определение loop в статье?
То, что в файле m.cpp, является более поздним и с ним данный фрагмент
не сработает.   Ваш вариант поиска я записал бы так:

loop (row = 0; col = 0 , row < MAXROW)
exitif (elem_at(row, col) != 0)
upd (if (++col == MAXCOL) { col = 0; ++row;})
fin();

Преимущества:
   проверка нахождения нужного элемента выделена самостоятельно;
   искомое условие для элемента сформулировано положительно;
   тело цикла не пусто;
   обновление индексов лучше сосредоточено в одной конструкции.

> Фишка этого примера в том, что он записывается целиком в рамках структурного 
> программирования: без goto, break и return.

Это если принять, что в структурном программировании их нет.
Но данная точка зрения не единственная.

> Плата за структурное программирование. В варианте Сергея Абрамова (в 
> следующем письме) вводится дополнительная булевская переменная и тоже 
> требуется дополнительная проверка

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

Плата за структурное программирование?  Скорее, по-моему, это
плата за определенное, очень конкретное понимание структурного
программирования.  Но единого определения этого понятия, с которым
все были бы согласны, нет.  Зачем подгонять решения задач под
какое-то представление о структурности, которое даже не является
общепризнанным?  Что получаем за «плату»?  Ведь решения становятся
в той или иной мере искусственными (признаком чего является
избыточность имен и действий), а что получаем навстречу и так ли
оно ценно?  Не лучше ли пересмотреть наше понимание о структурности?

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

Признано, что придерживаться какого-нибудь множества структурных схем
нужно, но по-моему так же нужно выбор этого множества время от времени
пересматривать.  Иначе в императивном программировании мы бы остались
с Фортраном или Алголом-60, у каждого из которых имеется единственный
оператор цикла.  А в функциональном программировании так и не пришли
бы к лексическому связыванию, частичному применению, одноаргументности
и композиции функций и сопоставлению с образцом — остались бы с Лиспом,
у которого их и сегодня нет, за исключением лексического связывания.

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


RE: FW: Рефал умер?

2017-08-08 Пенетрантность Александр Коновалов
Доброе утро, Бойко!

> Библиотекой назвать вряд ли стоит, там всего несколько макро- и шаблонных 
> определений.  Выложил здесь:
> http://www.math.bas.bg/bantchev/misc/m.cpp
> В следующем тексте написано немного об идеологии:
> http://www.math.bas.bg/bantchev/misc/neater.pdf , но он немного различается 
> как раз в отношении макроопределений для циклов.  Впрочем, в этом разберетесь 
> легко.

Посмотрел. Понравились макросы для отладочной печати. Буду пользоваться. На 
счёт циклов — в коммерческом ПО вряд ли, в своих проектах — возможно.

Понравилась реализация необязательного параметра n в макросе fora:

#define fora(a,i,n,...) {__VA_ARGS__; int _ = #n[0]=='\0' ? asize(a) : n+0; \
 for(int i=0; i<_; ++i) { // entire array processing

Когда его нет, #n раскрывается в пустую строчку, а n+0 в +0, что является 
корректным выражением. Не удивлюсь, если современные компиляторы истинность 
строки #n[0]=='\0' определят во время трансляции и во время выполнения 
ветвления уже не будет.

Мой пример выглядел бы так:

int row, col;  // используются после цикла, нельзя объявлять внутри.
loop (
  row = 0; col = 0
, row < MAXROW && elem_at(row, col) == 0
, ++col;
  if (col == MAXCOL) {
col = 0;
++row;
  }
)
  // тело пустое, как я и предполагал
fin();
Цикл с пустым телом.

Фишка этого примера в том, что он записывается целиком в рамках структурного 
программирования: без goto, break и return. И, кроме того, пример демонстрирует 
идиому структурного программирования для поиска элемента в последовательности:

<установить на начало>
while (! <достигли конца> && ! <элемент обнаружен>)
  <вычисление следующего и переход к нему>
if (<достигли конца>)
  <действия, если элемент не найден>
else
  <действия, если элемент найден>

Просто поразительно, как часто такой подход позволяет распутывать сложные 
циклы. Сам порой удивляюсь, что через эту идиому красиво описываются иные 
сложные задачи. Главное сформулировать задачу как задачу поиска. Сравнить две 
строки на равенство — _найти_ первый неравный символ, например.

А пример — поиск в двумерной таблице — потому и выбран, что большинство 
программистов не представляют, как его решить без двух вложенных циклов и 
нелокального перехода. Даже в учебниках его демонстрируют как пример, когда 
«goto необходимо».

> то, мне кажется, его легко переписать и стандартными for:
>
> for (row=0; row < MAXROW; ++row)
>   for (col=0; col < MAXCOL; ++col)
> if (elem_at(row,col)) goto x;
> x:
>
> По-моему, так текст и короче, и разобрать легче, а и выполняемых на каждом 
> шагу действий меньше.  Если goto очень раздражает (не меня), то можно и без 
> него:
>
> for (row=0; row < MAXROW; ++row) {
>   for (col=0; col < MAXCOL; ++col)
> if (elem_at(row,col)) break;
>   if (col < MAXCOL) break;
> }
Я знаю, в случаях со вложенными циклами в данном примере выполняется на одну 
проверку меньше. Плата за структурное программирование. В варианте Сергея 
Абрамова (в следующем письме) вводится дополнительная булевская переменная и 
тоже требуется дополнительная проверка. 

-Original Message-
From: Boyko Bantchev [mailto:boyk...@gmail.com] 
Sent: Tuesday, August 8, 2017 11:31 PM
To: refal@botik.ru
Subject: Re: FW: Рефал умер?

Здравствуйте, Александр!

> С интересом бы посмотрел на такую библиотеку макросов. Попробовал бы 
> переписать с её использованием два примера циклов while из предыдущего 
> письма. У вас она где-нибудь в интернете опубликована?

Библиотекой назвать вряд ли стоит, там всего несколько макро- и шаблонных 
определений.  Выложил здесь:
http://www.math.bas.bg/bantchev/misc/m.cpp

Чудес не ожидайте, вещи совсем простые.
С другой стороны, там не только о циклах, но и пара других, как мне кажется, 
полезных вещей.  Буду рад, если что-то вам пригодится.

В следующем тексте написано немного об идеологии:
http://www.math.bas.bg/bantchev/misc/neater.pdf , но он немного различается как 
раз в отношении макроопределений для циклов.  Впрочем, в этом разберетесь легко.

Что касается вашего первого примера с while

int row = 0, col = 0;
while (row < MAXROW && elem_at(row, col) == 0) {
  ++col;
  if (col == MAXCOL) {
col = 0;
++row;
  }
}

то, мне кажется, его легко переписать и стандартными for:

for (row=0; row < MAXROW; ++row)
  for (col=0; col < MAXCOL; ++col)
if (elem_at(row,col)) goto x;
x:

По-моему, так текст и короче, и разобрать легче, а и выполняемых на каждом шагу 
действий меньше.  Если goto очень раздражает (не меня), то можно и без него:

for (row=0; row < MAXROW; ++row) {
  for (col=0; col < MAXCOL; ++col)
if (elem_at(row,col)) break;
  if (col < MAXCOL) break;
}


Re: FW: Рефал умер?

2017-08-08 Пенетрантность Sergei M. Abramov
День добрый, всем!

> ... легко переписать и стандартными for:

> for (row=0; row < MAXROW; ++row)
>   for (col=0; col < MAXCOL; ++col)
> if (elem_at(row,col)) goto x;
> x:

> По-моему, так текст и короче, и разобрать легче, а и выполняемых на
> каждом шагу действий меньше.  Если goto очень раздражает (не меня),
> то можно и без него:

> for (row=0; row < MAXROW; ++row) {
>   for (col=0; col < MAXCOL; ++col)
> if (elem_at(row,col)) break;
>   if (col < MAXCOL) break;
> }

управление легко разменять на дополнительные переменные. Так докаывают
теорему о структурном программировании.

И я часто так делаю, примерно в таком стиле:

bool goon = true;
for (row=0; row < MAXROW && goon; ++row)
  for (col=0; col < MAXCOL && goon; ++col)
goon = elem_at(row,col) == 0;

Всего доброго,

Сергей Абрамов



Re: FW: Рефал умер?

2017-08-08 Пенетрантность Boyko Bantchev
Здравствуйте, Александр!

> С интересом бы посмотрел на такую библиотеку макросов. Попробовал бы 
> переписать с её использованием два примера циклов while из предыдущего 
> письма. У вас она где-нибудь в интернете опубликована?

Библиотекой назвать вряд ли стоит, там всего несколько макро- и
шаблонных определений.  Выложил здесь:
http://www.math.bas.bg/bantchev/misc/m.cpp

Чудес не ожидайте, вещи совсем простые.
С другой стороны, там не только о циклах, но и пара других, как мне
кажется, полезных вещей.  Буду рад, если что-то вам пригодится.

В следующем тексте написано немного об идеологии:
http://www.math.bas.bg/bantchev/misc/neater.pdf ,
но он немного различается как раз в отношении макроопределений для
циклов.  Впрочем, в этом разберетесь легко.

Что касается вашего первого примера с while

int row = 0, col = 0;
while (row < MAXROW && elem_at(row, col) == 0) {
  ++col;
  if (col == MAXCOL) {
col = 0;
++row;
  }
}

то, мне кажется, его легко переписать и стандартными for:

for (row=0; row < MAXROW; ++row)
  for (col=0; col < MAXCOL; ++col)
if (elem_at(row,col)) goto x;
x:

По-моему, так текст и короче, и разобрать легче, а и выполняемых на
каждом шагу действий меньше.  Если goto очень раздражает (не меня),
то можно и без него:

for (row=0; row < MAXROW; ++row) {
  for (col=0; col < MAXCOL; ++col)
if (elem_at(row,col)) break;
  if (col < MAXCOL) break;
}


RE: FW: Рефал умер?

2017-08-08 Пенетрантность Александр Коновалов
Здравствуйте, Бойко!

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

Вопрос вкуса и привычек.

> Да.  Однако это говорит о потребности в более усовершенствованной конструкции 
> типа for, а вовсе не об адекватности while для решения таких задач.

Наверное, да. Более развитый оператор цикла for мог бы собой заменить многие 
применения цикла while. И поднять выразительность программ.

> Кстати, повышать выразительность циклов в C и C++ можно за счет макросов — 
> тут и любое число локальных переменных, и развернутые 
> прологи/епилоги/обновления, и окончания непосредственно на синтаксическом 
> уровне тела цикла (чего break и continue не могут).
> Через макросы можно и специализировать (упрощать) циклы.  Я все это делал в 
> качестве эксперимента и даже считаю, что стоит пользоваться, когда нет 
> причин, заставляющих к обратному.

С интересом бы посмотрел на такую библиотеку макросов. Попробовал бы переписать 
с её использованием два примера циклов while из предыдущего письма. У вас она 
где-нибудь в интернете опубликована?


--
Александр Коновалов aka Маздайщик



Re: FW: Рефал умер?

2017-08-07 Пенетрантность Boyko Bantchev
Здравствуйте, Александр!

> Вот и выросло поколение, которое не пользуется почтовыми клиентами.

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

> Иногда логика продвижения, обновляющая часть сильно переплетена с логикой 
> обработки текущей итерации. Иногда продвижение выполняется как побочный 
> эффект проверки.

Согласен.  Но см. ниже.

> Иногда продвижение требует, скажем, условного оператора. А сишный for в 
> качестве операции обновления требует только одно выражение. При этом, 
> желательно, довольно короткое (выражение в три строки в операторе for будет 
> выглядеть и читаться не самым лучшим образом)

Да.  Однако это говорит о потребности в более усовершенствованной
конструкции типа for, а вовсе не об адекватности while для решения
таких задач.

Какое-то время назад я исследовал использование циклов в программах
на C.  Подтвердилось предположение о значительном доминировании
циклов с хорошо различимыми частьями, даже когда while.  Т.е. и в
теле многих while можно было четко разглядеть обновляющую часть,
а инициализация висела вне цикла, хотя по смыслу несомненно
относилась к нему.

Кстати, повышать выразительность циклов в C и C++ можно за счет
макросов — тут и любое число локальных переменных, и развернутые
прологи/епилоги/обновления, и окончания непосредственно на
синтаксическом уровне тела цикла (чего break и continue не могут).
Через макросы можно и специализировать (упрощать) циклы.  Я все это
делал в качестве эксперимента и даже считаю, что стоит пользоваться,
когда нет причин, заставляющих к обратному.


RE: FW: Рефал умер?

2017-08-07 Пенетрантность Александр Коновалов
Добрый день, Бойко!

> даже не выходя из браузера с имейлом :)
Вот и выросло поколение, которое не пользуется почтовыми клиентами. Я могу 
поиграть только с макросами VBA. :-)

> Но я и указывал на низкую частоту не употребления, а потребности в нем.
> Дело в том, что нередко программист поленится выделить, скажем, обновляющую 
> часть и соответственно применить for, а оставит ее в теле цикла while, 
> который пришел ему в голову первым.  Но при этом факт остается — по существу 
> требовалось for, а не while.

Не любую задачу имеет смысл втискивать в прокрустово ложе сишного for’а. Иногда 
логика продвижения, обновляющая часть сильно переплетена с логикой обработки 
текущей итерации. Иногда продвижение выполняется как побочный эффект проверки. 
Иногда продвижение требует, скажем, условного оператора. А сишный for в 
качестве операции обновления требует только одно выражение. При этом, 
желательно, довольно короткое (выражение в три строки в операторе for будет 
выглядеть и читаться не самым лучшим образом). А иногда и вовсе операция 
продвижения может целиком составлять тело цикла — на мой вкус тут лучше 
написать while, нежели for с длинным заголовком и пустым телом.

Например, поиск первого ненулевого элемента в двумерной таблице:

int row = 0, col = 0;
while (row < MAXROW && elem_at(row, col) == 0) {
  ++col;
  if (col == MAXCOL) {
col = 0;
++row;
  }
}

if (row == MAXROW) {
  ничего не нашли, обрабатываем этот случай
} else {
  обрабатываем случай, когда что-то нашли, скажем 30 строк кода.
}
освобождаем память, закрываем файлы, делаем другую общую очистку

Другой пример, посимвольная обработка файла:

FILE *f = fopen(…, "rb");
if (! f) {
  закрыть другие файлы, освободить память, return
}
int c;
while ((c = fgetc(f)) != EOF) {
  что-то делаем с символом
}
fclose(f);

В этих двух примерах на мой вкус лучше писать while (в последнем случае можно 
for, если хочется ограничить область видимости переменной int c).

> … место не копирование, а перемещение.  И вообще, даже избегая копипаст, 
> сохранять «копипастуемость» частей программы невредно.
Всецело поддерживаю этот тезис!

> И последнее, представим, что безымянный вызов реализован в каком-то языке в 
> виде особой переменной: в нормальном случае, если эта переменная встречается 
> в теле функции, она соответствует вызову той же функции.  Как и обсуждалось.  
> А теперь представим, что значение этой переменной можно в явном виде задать 
> при вызове функции — каким-то особым дополнительным аргументом или вообще 
> особым видом вызова.  Теперь уже эта переменная будет соответствовать не 
> вызванной функции, а некоторой другой.  (Подразумевается, что возможность 
> делать такие особые вызовы тоже встроена в языке.)
>
> Что получаем в итоге?
> Если вызывать функцию обычным способом, через свою особую переменную она 
> будет вызывать себя.  А если значение этой переменной подменить при помощи 
> специального вызова, то уже вызывать она будет того, кого ей указали.
Язык C# поддерживает необязательные и именованные параметры (выбрал первую 
попавшуюся ссылку):
http://www.quizful.net/interview/csharp/optional-named-parameters
Можно представить себе такое расширение C#’а, которое позволяет организовывать 
именно такую рекурсию. А именно, предположить, что любая функция принимает в 
качестве «скрытого» именованного параметра переменную rec (от слова recursion), 
которой по умолчанию присвоена сама эта функция. То есть в списке формальных 
параметров он явным образом не записывается, но внутри функции им пользоваться 
можно. А вот при вызове функции этот необязательный именованный параметр можно 
указать, передав ему совместимую функцию. Например, вызов f(3, 4) вызовет 
функцию f, и если функция f содержит вызов переменной rec, то она будет 
рекурсивно вызывать себя. Вызов же f(3, 4, rec: g) подменит переменную rec 
внутри неё. 

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

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

Здравствуйте, Александр!

Спасибо за комментарии!
Сделаю еще несколько заметок по теме.
Прошу прощения у тех, кому она неинтересна.

> В предыдущем письме вы привели пример кода на JavaScript, тем самым 
> подтолкнув меня в сторону императивной парадигмы. А там рекурсия 
> бывает редко

Я дал пример на JavaScript, потому что у данного языка имеется та конструкция, 
о которой говорил, при этом язык повсеместно распространен, так что 
приведенными примерами можно реально поиграть, даже не выходя из браузера с 
имейлом :)

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

Re: FW: Рефал умер?

2017-08-07 Пенетрантность Boyko Bantchev
> > > На мой взглад доступ с фреймам вызова функции через специальный объект
> > > в джаваскрипте - решение неудачное, так как оно не позволяет
> > > производить TCO. В функциональном языке какие-то варианты TCO очень
> > > важны, так как руками рекурсию в цикл превратить не получится.
> >
> > А я не понял: почему обсуждаемые конструкции мешают Tail Call Optimization?
> > По идее, если вызов действительно хвостовой (поверх него ничего нет),
> > то что мешает это заметить и преобразовать в цикл?
>
> Потому что от того, была выполнена эта оптимизация или нет, зависит
> семантика неконстантных методов объекта-функции. В исходном
> джаваскрипте TCO не было. Сейчас она допускается и для этого, как
> минимум, метод arguments у объектов-функций объявлен deprecated.

Так как и ответ я не совсем понял, и сам не в курсе с таким развитием языка
JavaScript, полюбопытствовал, заглянув в стандарт JavaScript — версии
2015 и 2017 года.  Последняя здесь:
http://ecma-international.org/publications/standards/Ecma-262.htm.
Это тоже не помогло прояснить ситуацию, так как слово deprecated там
вообще не встречается, а читать всё подряд не стал.

Но должен уточнить: вопрос о возможном удалении чего-то из JavaScript
и не имеет никакого отношения к сути того, о чем я писал.

То, что я обсуждал, это возможность безымянной функции цитировать себя.
Это по существу синтаксическое средство и ненужно его связывать с
«фреймами вызова» — функции незачем ждать быть вызванной, чтобы узнать
кто она; она это должна знать с рождения.

А что в JavaScript, на котором давал примеры, имеются свои особенности,
к вопросу совершенно несущественно.

П.П.  Только что видел, что и Андрей Климов писал о том же.


Re: FW: Рефал умер?

2017-08-07 Пенетрантность Andrei Klimov
;> > whileTrue: f3 := [x < y]. f4 := […]. f3 whileTrue: f4..
> >> >
> >> > Когда я это объяснял студентам (и делал замены из предыдущего абзаца),
> >> > только что написавшим (и правильно написавшим) лабораторную, они
> удивлялись.
> >> > Оказывалось, что в языке нет управляющих конструкций кроме создания
> блока,
> >> > вызова метода и ^ (так обозначается возврат из метода). Ветвление и
> цикл —
> >> > методы библиотечных классов.
> >> >
> >> > Это я рассказал к тому, что безымянные функции вкупе с функциями
> >> > стандартной библиотеки (map, fold, filter и другие) воспринимаются как
> >> > цельные синтаксические конструкции, фактически, как встроенные
> операторы
> >> > языка. Помимо Smalltalk’а (а он позиционируется как
> >> > объектно-ориентированный, а не функциональный), могучая синтаксическая
> >> > поддержка таких конструкций есть в Ruby и Kotlin’е (не
> программировал, могу
> >> > что-то путать ошибаться). В последнем, например, если функция/метод
> >> > принимает последним аргументом функцию, то её можно записывать как
> просто
> >> > блок в фигурных скобках _вне_ круглых скобок: вместо foo(x, y, {…})
> можно
> >> > писать foo(x, y) {…}. Если аргумент единственный — скобки не нужны:
> foo({…})
> >> > эквивалентно foo {…}. Что и позволяет писать конструкции, выглядящие
> почти
> >> > как нативные синтаксические конструкции (типа if(…) {…}).
> >> >
> >> > -Original Message-
> >> > From: Boyko Bantchev [mailto:boyk...@gmail.com]
> >> > Sent: Friday, August 4, 2017 10:28 AM
> >> > To: refal@botik.ru
> >> > Subject: Re: FW: Рефал умер?
> >> >
> >> > Здравствуйте, Александр!
> >> >
> >> >> Вы не могли бы пояснить, что вы имеете ввиду под «цитированием себя и
> >> >> охватывающей функции при помощи … стандартной пары знаков или имён»?
> >> >
> >> > Имею ввиду возможность, заложенную в языке, любой функции вызывать
> себя
> >> > через какое-то фиксированное, универсальное для этой роли имя.
> >> > Ну, или передавать свой адрес кому-то еще.  Подобно местоимениям «я»
> или
> >> > «себя»/«себе» в человеческой речи — человек говорит о себе, не
> нуждаясь в
> >> > имени.  Местоимение одно и то же, но относится к разным людям в
> зависимости
> >> > от того, кто говорит.  Конкретный синтаксис неважен.
> >> >
> >> > Один из совсем немногих языков, где это имеется — это JavaScript.
> >> > Дам пример на нем.
> >> >
> >> > В этом языке у каждой функций имеется (составная) переменная
> arguments,
> >> > а у arguments имеется часть callee.  Так вот, arguments.callee — это
> то, о
> >> > чем я говорю.  В результате можно написать, скажем, анонимный
> рекурсивный
> >> > факториал:
> >> >
> >> > function(n) {return n<2 ? 1 : n*arguments.callee(n-1)}
> >> >
> >> > и вызвать его можно так:
> >> >
> >> > (function(n) {return n<2 ? 1 : n*arguments.callee(n-1)})(5)
> >> >
> >> > (или передать кому-нибудь как значение, а вызывать будет уже он сам).
> >> >
> >> > Еще пример: обращение связанного списка функцией reverse.
> >> > reverse создает вложенную функцию с двумя аргументами (из первого она
> >> > накапливает результат во второй) и тут же ее вызывает.  Вложенная
> функция
> >> > рекурсивна и анонимна.
> >> >
> >> > function reverse(x) {
> >> >   return (function(x,y) {
> >> > if (x) {
> >> >   var r = x
> >> >   x = x.next
> >> >   r.next = y
> >> >   return arguments.callee(x,r)
> >> > }
> >> > return y
> >> >   })(x,null)
> >> > }
> >> >
> >> > (А список может быть, скажем, такой:
> >> >
> >> > list = {data:1}
> >> > list = {data:2, next:list}
> >> > list = {data:3, next:list}
> >> > )
> >> >
> >> > Иногда полезно подобным стандартным анонимным образом вызывать и
> >> > охватывающую функцию, возможно даже и ту, которая, в свою очередь, ее
> >> > охватывает — это позволяет уже взаимную анонимную рекурсию, но таких
> средств
> >> > ни в JavaScript, ни в других языках не видел.  (Сам я такое свойство
> вложил
> >> > в своем полуреализованном языке, но миру от этого мало пользы :) )
> >> >
> >> > Бойко
>


Re: FW: Рефал умер?

2017-08-07 Пенетрантность Mike Potanin
y и Kotlin’е (не программировал, могу
>> > что-то путать ошибаться). В последнем, например, если функция/метод
>> > принимает последним аргументом функцию, то её можно записывать как просто
>> > блок в фигурных скобках _вне_ круглых скобок: вместо foo(x, y, {…}) можно
>> > писать foo(x, y) {…}. Если аргумент единственный — скобки не нужны: 
>> > foo({…})
>> > эквивалентно foo {…}. Что и позволяет писать конструкции, выглядящие почти
>> > как нативные синтаксические конструкции (типа if(…) {…}).
>> >
>> > -Original Message-
>> > From: Boyko Bantchev [mailto:boyk...@gmail.com]
>> > Sent: Friday, August 4, 2017 10:28 AM
>> > To: refal@botik.ru
>> > Subject: Re: FW: Рефал умер?
>> >
>> > Здравствуйте, Александр!
>> >
>> >> Вы не могли бы пояснить, что вы имеете ввиду под «цитированием себя и
>> >> охватывающей функции при помощи … стандартной пары знаков или имён»?
>> >
>> > Имею ввиду возможность, заложенную в языке, любой функции вызывать себя
>> > через какое-то фиксированное, универсальное для этой роли имя.
>> > Ну, или передавать свой адрес кому-то еще.  Подобно местоимениям «я» или
>> > «себя»/«себе» в человеческой речи — человек говорит о себе, не нуждаясь в
>> > имени.  Местоимение одно и то же, но относится к разным людям в зависимости
>> > от того, кто говорит.  Конкретный синтаксис неважен.
>> >
>> > Один из совсем немногих языков, где это имеется — это JavaScript.
>> > Дам пример на нем.
>> >
>> > В этом языке у каждой функций имеется (составная) переменная arguments,
>> > а у arguments имеется часть callee.  Так вот, arguments.callee — это то, о
>> > чем я говорю.  В результате можно написать, скажем, анонимный рекурсивный
>> > факториал:
>> >
>> > function(n) {return n<2 ? 1 : n*arguments.callee(n-1)}
>> >
>> > и вызвать его можно так:
>> >
>> > (function(n) {return n<2 ? 1 : n*arguments.callee(n-1)})(5)
>> >
>> > (или передать кому-нибудь как значение, а вызывать будет уже он сам).
>> >
>> > Еще пример: обращение связанного списка функцией reverse.
>> > reverse создает вложенную функцию с двумя аргументами (из первого она
>> > накапливает результат во второй) и тут же ее вызывает.  Вложенная функция
>> > рекурсивна и анонимна.
>> >
>> > function reverse(x) {
>> >   return (function(x,y) {
>> > if (x) {
>> >   var r = x
>> >   x = x.next
>> >   r.next = y
>> >   return arguments.callee(x,r)
>> > }
>> > return y
>> >   })(x,null)
>> > }
>> >
>> > (А список может быть, скажем, такой:
>> >
>> > list = {data:1}
>> > list = {data:2, next:list}
>> > list = {data:3, next:list}
>> > )
>> >
>> > Иногда полезно подобным стандартным анонимным образом вызывать и
>> > охватывающую функцию, возможно даже и ту, которая, в свою очередь, ее
>> > охватывает — это позволяет уже взаимную анонимную рекурсию, но таких 
>> > средств
>> > ни в JavaScript, ни в других языках не видел.  (Сам я такое свойство вложил
>> > в своем полуреализованном языке, но миру от этого мало пользы :) )
>> >
>> > Бойко


Re: FW: Рефал умер?

2017-08-07 Пенетрантность Andrei Klimov
Михаил,

А я не понял: почему обсуждаемые конструкции мешают Tail Call Optimization?
По идее, если вызов действительно хвостовой (поверх него ничего нет), то
что мешает это заметить и преобразовать в цикл?

Андрей

7 авг. 2017 г. 11:20 пользователь "Mike Potanin" 
написал:

> На мой взглад доступ с фреймам вызова функции через специальный объект
> в джаваскрипте - решение неудачное, так как оно не позволяет
> производить TCO. В функциональном языке какие-то варианты TCO очень
> важны, так как руками рекурсию в цикл превратить не получится.
>
> 2017-08-04 23:56 GMT+03:00 Александр Коновалов :
> > Добрый вечер, Бойко!
> >
> > Понял вашу мысль. Вы фактически предлагаете аналог указателя «this» (или
> «self») применительно к безымянным функциям. Идея интересная, но у меня
> затык не с синтаксической конструкцией, а с представлением во время
> выполнения. Хоть с именами, хоть с this’ом взаимная рекурсия с возвратом
> указателя неизбежно конфликтует (а) с требованиями к равенству двух
> указателей на функцию, (б) с использованием простого счётчика ссылок для
> управления памятью.
> >
> > Почему нет такой конструкции в большинстве языков программирования?
> Во-первых, инертность мышления (а что, и так тоже можно?), во-вторых, нужна
> редко. Обычно ко вложенной безымянной функции относятся не как к функции, а
> как к блоку кода, который воспринимается как некий фрагмент устойчивой
> конструкции, функции map, играющей роль цикла. Вложенные безымянные функции
> обычно небольшие и играют роль части выражения. Если нужно выразить более
> сложную логику, то её оформляют как отдельную функцию, которой уже логично
> дать соответствующее имя (независимо от наличия рекурсии внутри). Вообще,
> лучший способ прокомментировать блок кода — не писать комментарий перед
> ним, а вынести его в отдельную функцию и дать ей ясное понятное название.
> >
> >
> > Не могу не поделиться одной историей. В этом году я разрешил студентам
> сдавать лабораторные на необычных языка программирования, при этом одна
> лабораторная засчитывалась за три. Среди таких языков был Smalltalk. Порог
> вхождения у него низкий: посмотрев на примеры кода и найдя документацию по
> стандартной библиотеке, уже можно писать немаленькие (сотни строк кода)
> работающие программы. При этом вникать в устройство языка не обязательно.
> >
> > Так вот. «Условный оператор» в Smalltalk выглядит так: (x < y) ifTrue:
> […] ifFalse: […]., «цикл» — [x < y] whileTrue: […].. Так вот. Это не
> условный оператор и не цикл. Текст в квадратных скобках — это не блок кода
> (как {…} в C++), а лямбда. Безымянная функция (вернее, безымянный класс с
> методом call, если я ничего не путаю). Булевский класс имеет двух потомков,
> соответственно, True и False. У первого метод ifTrue: f1 ifFalse f2.
> выполняет замыкание f1, у второго — f2. У самого класса замыкания, помимо
> метода call, есть метод whileTrue: func., который вычисляет себя и свой
> аргумент в цикле, пока сам себе возвращает значение True.
> >
> > А значит, вместо (x < y) ifTrue: […] ifFalse: [……]. можно написать: f1
> := […]. f2 := [……]. (x < y) ifTrue: f1 ifFalse f2. Аналогично с «циклом»
> whileTrue: f3 := [x < y]. f4 := […]. f3 whileTrue: f4..
> >
> > Когда я это объяснял студентам (и делал замены из предыдущего абзаца),
> только что написавшим (и правильно написавшим) лабораторную, они
> удивлялись. Оказывалось, что в языке нет управляющих конструкций кроме
> создания блока, вызова метода и ^ (так обозначается возврат из метода).
> Ветвление и цикл — методы библиотечных классов.
> >
> > Это я рассказал к тому, что безымянные функции вкупе с функциями
> стандартной библиотеки (map, fold, filter и другие) воспринимаются как
> цельные синтаксические конструкции, фактически, как встроенные операторы
> языка. Помимо Smalltalk’а (а он позиционируется как
> объектно-ориентированный, а не функциональный), могучая синтаксическая
> поддержка таких конструкций есть в Ruby и Kotlin’е (не программировал, могу
> что-то путать ошибаться). В последнем, например, если функция/метод
> принимает последним аргументом функцию, то её можно записывать как просто
> блок в фигурных скобках _вне_ круглых скобок: вместо foo(x, y, {…}) можно
> писать foo(x, y) {…}. Если аргумент единственный — скобки не нужны:
> foo({…}) эквивалентно foo {…}. Что и позволяет писать конструкции,
> выглядящие почти как нативные синтаксические конструкции (типа if(…) {…}).
> >
> > -Original Message-
> > From: Boyko Bantchev [mailto:boyk...@gmail.com]
> > Sent: Friday, August 4, 2017 10:28 AM
> > To: refal@botik.ru
> > Subject: Re: FW: Рефал умер?
> >
> > Здравствуйте, Александр!
> >
> >> Вы не могли бы пояснить, что вы имее

Re: FW: Рефал умер?

2017-08-07 Пенетрантность Boyko Bantchev
Здравствуйте, Александр!

Спасибо за комментарии!
Сделаю еще несколько заметок по теме.
Прошу прощения у тех, кому она неинтересна.

> В предыдущем письме вы привели пример кода на JavaScript, тем самым 
> подтолкнув меня в сторону императивной парадигмы. А там рекурсия бывает редко

Я дал пример на JavaScript, потому что у данного языка имеется
та конструкция, о которой говорил, при этом язык повсеместно
распространен, так что приведенными примерами можно реально
поиграть, даже не выходя из браузера с имейлом :)

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

По поводу частоты циклов while в Си-подобных ЯП: вы привели статистику,
чтобы показать, что while встречается нередко, с чем я вполне согласен.
Но я и указывал на низкую частоту не употребления, а потребности в нем.
(Прошу, обратите внимание на мои слова, которые вы цитировали до
статистики.)  Дело в том, что нередко программист поленится выделить,
скажем, обновляющую часть и соответственно применить for, а оставит ее
в теле цикла while, который пришел ему в голову первым.  Но при этом
факт остается — по существу требовалось for, а не while.

Выражаясь крайным образом, можно сказать так: цикл с условием, но без
обновляющей части вообще невозможен, так как, если значения участвующих
в условии переменных не обновляются, цикл не завершится :)

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

> Копипаст — зло.

В целом — да.  Но бывает и так, что копипаст сопровождается удалением
оригинала, т.е. имеет место не копирование, а перемещение.  И вообще,
даже избегая копипаст, сохранять «копипастуемость» частей программы
невредно.

Наконец, приведу еще две соображения в пользу безымянного самовызова.

Пусть мы написали функцию для чего-то — небольшую, но с рекурсией.
Хотелось бы функцию не именовать, так как она используется лишь в
одном месте, где она вызывается или передается как значение или
результат другой функции.  Но в отсутствии возможности безымянного
самовызова именовать требует рекурсия.  А потом вдруг спохватились,
что данная функция — всего лишь fold или zip и т.д., и переписали,
и уже именовать не требуется, так как и рекурсии нет.  Но тогда что
получается?  Именовать или нет зависит не от значительности функции
или других факторов, а полностью от наличия в ее реализации рекурсии.
Способ реализации диктует не относящиеся к реализации решения!

И последнее, представим, что безымянный вызов реализован в каком-то
языке в виде особой переменной: в нормальном случае, если эта
переменная встречается в теле функции, она соответствует вызову той
же функции.  Как и обсуждалось.  А теперь представим, что значение
этой переменной можно в явном виде задать при вызове функции —
каким-то особым дополнительным аргументом или вообще особым видом
вызова.  Теперь уже эта переменная будет соответствовать не вызванной
функции, а некоторой другой.  (Подразумевается, что возможность делать
такие особые вызовы тоже встроена в языке.)

Что получаем в итоге?
Если вызывать функцию обычным способом, через свою особую переменную
она будет вызывать себя.  А если значение этой переменной подменить
при помощи специального вызова, то уже вызывать она будет того, кого
ей указали.

Последнее знакомо?  Это как раз то преобразование функции, которое
мы делаем, чтобы к этой функции применить комбинатор Y или функцию,
которая сделает из нее ее мемо-вариант.  И Y, и мемо-генератор делают
свою работу вполне автономно, но им обоим нужно подать подходящим
образом уже преобразованную функцию.  А поскольку этот начальный шаг
пока делается вручную, ни нахождение неподвижной точки, ни переход
от функции к ее мемо-варианту не могут быть вполне автоматическими
процессами.  Мое предложение устраняет данное неудобство.  Понятно,
что его применимость этим не ограничена — оно скажется положительно
и на другие преобразования рекурсивных функций.

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


Re: FW: Рефал умер?

2017-08-07 Пенетрантность Mike Potanin
На мой взглад доступ с фреймам вызова функции через специальный объект
в джаваскрипте - решение неудачное, так как оно не позволяет
производить TCO. В функциональном языке какие-то варианты TCO очень
важны, так как руками рекурсию в цикл превратить не получится.

2017-08-04 23:56 GMT+03:00 Александр Коновалов :
> Добрый вечер, Бойко!
>
> Понял вашу мысль. Вы фактически предлагаете аналог указателя «this» (или 
> «self») применительно к безымянным функциям. Идея интересная, но у меня затык 
> не с синтаксической конструкцией, а с представлением во время выполнения. 
> Хоть с именами, хоть с this’ом взаимная рекурсия с возвратом указателя 
> неизбежно конфликтует (а) с требованиями к равенству двух указателей на 
> функцию, (б) с использованием простого счётчика ссылок для управления памятью.
>
> Почему нет такой конструкции в большинстве языков программирования? 
> Во-первых, инертность мышления (а что, и так тоже можно?), во-вторых, нужна 
> редко. Обычно ко вложенной безымянной функции относятся не как к функции, а 
> как к блоку кода, который воспринимается как некий фрагмент устойчивой 
> конструкции, функции map, играющей роль цикла. Вложенные безымянные функции 
> обычно небольшие и играют роль части выражения. Если нужно выразить более 
> сложную логику, то её оформляют как отдельную функцию, которой уже логично 
> дать соответствующее имя (независимо от наличия рекурсии внутри). Вообще, 
> лучший способ прокомментировать блок кода — не писать комментарий перед ним, 
> а вынести его в отдельную функцию и дать ей ясное понятное название.
>
>
> Не могу не поделиться одной историей. В этом году я разрешил студентам 
> сдавать лабораторные на необычных языка программирования, при этом одна 
> лабораторная засчитывалась за три. Среди таких языков был Smalltalk. Порог 
> вхождения у него низкий: посмотрев на примеры кода и найдя документацию по 
> стандартной библиотеке, уже можно писать немаленькие (сотни строк кода) 
> работающие программы. При этом вникать в устройство языка не обязательно.
>
> Так вот. «Условный оператор» в Smalltalk выглядит так: (x < y) ifTrue: […] 
> ifFalse: […]., «цикл» — [x < y] whileTrue: […].. Так вот. Это не условный 
> оператор и не цикл. Текст в квадратных скобках — это не блок кода (как {…} в 
> C++), а лямбда. Безымянная функция (вернее, безымянный класс с методом call, 
> если я ничего не путаю). Булевский класс имеет двух потомков, соответственно, 
> True и False. У первого метод ifTrue: f1 ifFalse f2. выполняет замыкание f1, 
> у второго — f2. У самого класса замыкания, помимо метода call, есть метод 
> whileTrue: func., который вычисляет себя и свой аргумент в цикле, пока сам 
> себе возвращает значение True.
>
> А значит, вместо (x < y) ifTrue: […] ifFalse: [……]. можно написать: f1 := 
> […]. f2 := [……]. (x < y) ifTrue: f1 ifFalse f2. Аналогично с «циклом» 
> whileTrue: f3 := [x < y]. f4 := […]. f3 whileTrue: f4..
>
> Когда я это объяснял студентам (и делал замены из предыдущего абзаца), только 
> что написавшим (и правильно написавшим) лабораторную, они удивлялись. 
> Оказывалось, что в языке нет управляющих конструкций кроме создания блока, 
> вызова метода и ^ (так обозначается возврат из метода). Ветвление и цикл — 
> методы библиотечных классов.
>
> Это я рассказал к тому, что безымянные функции вкупе с функциями стандартной 
> библиотеки (map, fold, filter и другие) воспринимаются как цельные 
> синтаксические конструкции, фактически, как встроенные операторы языка. 
> Помимо Smalltalk’а (а он позиционируется как объектно-ориентированный, а не 
> функциональный), могучая синтаксическая поддержка таких конструкций есть в 
> Ruby и Kotlin’е (не программировал, могу что-то путать ошибаться). В 
> последнем, например, если функция/метод принимает последним аргументом 
> функцию, то её можно записывать как просто блок в фигурных скобках _вне_ 
> круглых скобок: вместо foo(x, y, {…}) можно писать foo(x, y) {…}. Если 
> аргумент единственный — скобки не нужны: foo({…}) эквивалентно foo {…}. Что и 
> позволяет писать конструкции, выглядящие почти как нативные синтаксические 
> конструкции (типа if(…) {…}).
>
> -Original Message-
> From: Boyko Bantchev [mailto:boyk...@gmail.com]
> Sent: Friday, August 4, 2017 10:28 AM
> To: refal@botik.ru
> Subject: Re: FW: Рефал умер?
>
> Здравствуйте, Александр!
>
>> Вы не могли бы пояснить, что вы имеете ввиду под «цитированием себя и
>> охватывающей функции при помощи … стандартной пары знаков или имён»?
>
> Имею ввиду возможность, заложенную в языке, любой функции вызывать себя через 
> какое-то фиксированное, универсальное для этой роли имя.
> Ну, или передавать свой адрес кому-то еще.  Подобно местоимениям «я» или 
> «себя»/«себе» в человеческой речи — человек говорит о себе, н

RE: FW: Рефал умер?

2017-08-06 Пенетрантность Александр Коновалов
рых ассемблеров.
* Ввести конструкцию, не требующую именованной метки: структурный цикл, 
подразумевающий в конце переход в начало, замаскированные goto, связываемые с 
ближайшим окружающим циклом — break и continue. К слову, развитием этой мысли 
являются break и continue с метками, например, в Java.
Фактически, вы предлагаете конструкцию, аналогичную continue, но для рекурсии 
(аналог break уже есть, называется return).

> В плане практическом, возьмем такую ситуацию.  Часто бывает так, что вызов 
> рекурсивной функции ее пользователем отличается от самовызова — например, 
> из-за того, что при первом вызове нужно что-то сделать один
раз: как правило, установить какие-то начальные значения.  Но чаще всего, 
вызываемой функции нечем отличить первый вызов от самовызовов, а даже если это 
возможно, то невыгодно проверять каждый раз.
> Это противоречие устраняется вложением в основную функцию «вспомогательной», 
> которая на самом деле выполняет работу по существу и, в частности, 
> самовызывается рекурсивно.  «Основная» же функция только подготавливает 
> начальные параметры к ее работе и, возможно, как-то изменяет результат до 
> того как передать его пользователю.
До боли знакомая ситуация. Я много программировал на Базисном Рефале, где из 
управляющих конструкций есть только функции, и эти функции глобальны. Функция 
служит и ветвлением (выбор осуществляется сопоставлением с одним из образцов), 
и циклом (рекурсия). И обычной ситуацией является запись какой-то повторяющейся 
операции в виде двух функций. Одна служит «фасадом» — принимает значимые 
аргументы, вторая — циклом. «Фасад» подготавливает для «цикла» дополнительные 
переменные-аккумуляторы, которые хранят своё значение между итерациями.
Если бы я программировал на Рефале с именованными вложенными функциями, и там 
бы мне потребовался бы цикл, то я написал бы: $func Loop { …… }. А внутри 
функции вызывал бы . Для дважды вложенных функций использовал бы имена 
вроде Loop-ЧтоТоОдно, Loop-ЧтоТоДругое. Сейчас подумываю о соответствующих 
ключевых словах, например <$repeat …>, <$repeat0 …> (синоним $repeat), 
<$repeat1 …> (для окружающей)… Либо, <$loop …>, <$rec …> или какое-нибудь иное 
слово. Вообще, такое ключевое слово можно использовать и в обычных глобальных 
именованных функциях для рекурсивного вызова. Тоже смотрелось бы неплохо.

В общем, вы предложили благодатную идею для функциональных языков вообще, и для 
Рефала в частности. Мне нравится.

> …а вложенную функцию можно даже скопировать в другое подходящее окружение, не 
> изменяя ничего в ней, в частности — интерфейс к «родителю».
Копипаст — зло. Если нужно скопировать код, чтобы повторить одинаковую логику, 
то эту логику нужно вынести в отдельную функцию, которую следует вызывать из 
двух мест. А функция будет именованной :-). Впрочем, если язык поддерживает 
макросы, то можно такой фрагмент кода использовать внутри макроса. Пишут же на 
Си макросы, содержащие, скажем, break, continue или return.

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

Здравствуйте, Александр,

> Почему нет такой конструкции в большинстве языков программирования? 
> Во-первых, инертность мышления (а что, и так тоже можно?), во-вторых, нужна 
> редко. Обычно ко вложенной безымянной функции относятся не как к функции, а 
> как к блоку кода, который воспринимается как некий фрагмент устойчивой 
> конструкции, функции map, играющей роль цикла. Вложенные безымянные функции 
> обычно небольшие и играют роль части выражения. Если нужно выразить более 
> сложную логику, то её оформляют как отдельную функцию, которой уже логично 
> дать соответствующее имя (независимо от наличия рекурсии внутри). Вообще, 
> лучший способ прокомментировать блок кода — не писать комментарий перед ним, 
> а вынести его в отдельную функцию и дать ей ясное понятное название.

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

Вот, например, в истинности утверждения

«лучший способ прокомментировать блок кода — не писать комментарий
 перед ним, а вынести его в отдельную функцию и дать ей ясное
 понятное название»

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

Более того, вы пишете, что возможность самоцитирования (и цитирования 
охватывающей функции) для безымянных функций «нужна редко».  С этим тоже не 
могу согласиться.  В 

Re: FW: Рефал умер?

2017-08-05 Пенетрантность Boyko Bantchev
Здравствуйте, Александр,

> Почему нет такой конструкции в большинстве языков программирования? 
> Во-первых, инертность мышления (а что, и так тоже можно?), во-вторых, нужна 
> редко. Обычно ко вложенной безымянной функции относятся не как к функции, а 
> как к блоку кода, который воспринимается как некий фрагмент устойчивой 
> конструкции, функции map, играющей роль цикла. Вложенные безымянные функции 
> обычно небольшие и играют роль части выражения. Если нужно выразить более 
> сложную логику, то её оформляют как отдельную функцию, которой уже логично 
> дать соответствующее имя (независимо от наличия рекурсии внутри). Вообще, 
> лучший способ прокомментировать блок кода — не писать комментарий перед ним, 
> а вынести его в отдельную функцию и дать ей ясное понятное название.

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

Вот, например, в истинности утверждения

«лучший способ прокомментировать блок кода — не писать комментарий
 перед ним, а вынести его в отдельную функцию и дать ей ясное
 понятное название»

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

Более того, вы пишете, что возможность самоцитирования (и цитирования
охватывающей функции) для безымянных функций «нужна редко».  С этим
тоже не могу согласиться.  В своем утверждении вы исходите из своих
же представлений о роли и использовании функций.  Они, конечно, не
лишены основания, но мне кажутся несколько размытыми.  Что есть
«фрагмент», который не функция в функциональном языке?  Какая именно
логика является «более сложной»?  По какому критерию «логично»
закреплять имя за функцией как часть ее реализации (а не только
интерфейса — ведь когда имя рекурсивной функции цитируется в ее теле
это касается реализации)?  На такие вопросы, полагаю, ответить можно
по-разному, поэтому и выводы будут неоднозначными.

(Впрочем, по поводу утверждения «нужна редко», вспомнил о цикле со
след-условием (do-while или repeat-until).  Он часто используется?
Судя по моей практике, крайне редко.  Тем не менее, он есть в почти
всех императивных языках.  А зачем нужен while в языке C и подобных,
когда он — всего лишь частный случай for, с тяжелыми ограничениями?
Насколько часто нужно написать цикл без ни вводной, ни обновляющей
частей?  По-моему, очень редко.  Но и эта конструкция присутствует
практически везде в императивных языках.)

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

Свои соображения в пользу возможности _не_именования любых функций,
в т.ч. рекурсивных, я разделяю на две группы — принципиальные и
практические.

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

Также принципиальным является отличие функции, которая является
значением, от функции с закрепленным в ее теле ее же именем.  Тело
первой функции можно подставить везде, где требуется ее значение
(для вызова или другой цели) — отсюда, в частности, вытекает удобство
механических манипуляций с программой — а со второй так сделать
невозможно.  Уместно ли обязательно ставить функцию во второй,
ограниченный класс, только потому что она рекурсивная?

В плане практическом, возьмем такую ситуацию.  Часто бывает так, что
вызов рекурсивной функции ее пользователем отличается от самовызова —
например, из-за того, что при первом вызове нужно что-то сделать один
раз: как правило, установить какие-то начальные значения.  Но чаще
всего, вызываемой функции нечем отличить первый вызов от самовызовов,
а даже если это возможно, то невыгодно проверять каждый раз.
Это противоречие устраняется вложением в основную функцию
«вспомогательной», которая на самом деле выполняет работу по существу
и, в частности, самовызывается рекурсивно.  «Основная» же функция
только подготавливает начальные параметры к ее работе и, возможно,
как-то изменяет результат до того как передать его пользователю.
(Второй данный мной раньше пример (с обращением списка) — именно
такой случай.)  Но тогда получается так, что вложенную функцию мы
именуем только для того, чтобы она могла себя вызывать; имя ее
пользователю основной функции не нужно.  А может быть и так, чт

RE: FW: Рефал умер?

2017-08-04 Пенетрантность Александр Коновалов
Добрый вечер, Бойко!

Понял вашу мысль. Вы фактически предлагаете аналог указателя «this» (или 
«self») применительно к безымянным функциям. Идея интересная, но у меня затык 
не с синтаксической конструкцией, а с представлением во время выполнения. Хоть 
с именами, хоть с this’ом взаимная рекурсия с возвратом указателя неизбежно 
конфликтует (а) с требованиями к равенству двух указателей на функцию, (б) с 
использованием простого счётчика ссылок для управления памятью.

Почему нет такой конструкции в большинстве языков программирования? Во-первых, 
инертность мышления (а что, и так тоже можно?), во-вторых, нужна редко. Обычно 
ко вложенной безымянной функции относятся не как к функции, а как к блоку кода, 
который воспринимается как некий фрагмент устойчивой конструкции, функции map, 
играющей роль цикла. Вложенные безымянные функции обычно небольшие и играют 
роль части выражения. Если нужно выразить более сложную логику, то её оформляют 
как отдельную функцию, которой уже логично дать соответствующее имя (независимо 
от наличия рекурсии внутри). Вообще, лучший способ прокомментировать блок кода 
— не писать комментарий перед ним, а вынести его в отдельную функцию и дать ей 
ясное понятное название.


Не могу не поделиться одной историей. В этом году я разрешил студентам сдавать 
лабораторные на необычных языка программирования, при этом одна лабораторная 
засчитывалась за три. Среди таких языков был Smalltalk. Порог вхождения у него 
низкий: посмотрев на примеры кода и найдя документацию по стандартной 
библиотеке, уже можно писать немаленькие (сотни строк кода) работающие 
программы. При этом вникать в устройство языка не обязательно.

Так вот. «Условный оператор» в Smalltalk выглядит так: (x < y) ifTrue: […] 
ifFalse: […]., «цикл» — [x < y] whileTrue: […].. Так вот. Это не условный 
оператор и не цикл. Текст в квадратных скобках — это не блок кода (как {…} в 
C++), а лямбда. Безымянная функция (вернее, безымянный класс с методом call, 
если я ничего не путаю). Булевский класс имеет двух потомков, соответственно, 
True и False. У первого метод ifTrue: f1 ifFalse f2. выполняет замыкание f1, у 
второго — f2. У самого класса замыкания, помимо метода call, есть метод 
whileTrue: func., который вычисляет себя и свой аргумент в цикле, пока сам себе 
возвращает значение True.

А значит, вместо (x < y) ifTrue: […] ifFalse: [……]. можно написать: f1 := […]. 
f2 := [……]. (x < y) ifTrue: f1 ifFalse f2. Аналогично с «циклом» whileTrue: f3 
:= [x < y]. f4 := […]. f3 whileTrue: f4..

Когда я это объяснял студентам (и делал замены из предыдущего абзаца), только 
что написавшим (и правильно написавшим) лабораторную, они удивлялись. 
Оказывалось, что в языке нет управляющих конструкций кроме создания блока, 
вызова метода и ^ (так обозначается возврат из метода). Ветвление и цикл — 
методы библиотечных классов.

Это я рассказал к тому, что безымянные функции вкупе с функциями стандартной 
библиотеки (map, fold, filter и другие) воспринимаются как цельные 
синтаксические конструкции, фактически, как встроенные операторы языка. Помимо 
Smalltalk’а (а он позиционируется как объектно-ориентированный, а не 
функциональный), могучая синтаксическая поддержка таких конструкций есть в Ruby 
и Kotlin’е (не программировал, могу что-то путать ошибаться). В последнем, 
например, если функция/метод принимает последним аргументом функцию, то её 
можно записывать как просто блок в фигурных скобках _вне_ круглых скобок: 
вместо foo(x, y, {…}) можно писать foo(x, y) {…}. Если аргумент единственный — 
скобки не нужны: foo({…}) эквивалентно foo {…}. Что и позволяет писать 
конструкции, выглядящие почти как нативные синтаксические конструкции (типа 
if(…) {…}).

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

Здравствуйте, Александр!

> Вы не могли бы пояснить, что вы имеете ввиду под «цитированием себя и 
> охватывающей функции при помощи … стандартной пары знаков или имён»?

Имею ввиду возможность, заложенную в языке, любой функции вызывать себя через 
какое-то фиксированное, универсальное для этой роли имя.
Ну, или передавать свой адрес кому-то еще.  Подобно местоимениям «я» или 
«себя»/«себе» в человеческой речи — человек говорит о себе, не нуждаясь в 
имени.  Местоимение одно и то же, но относится к разным людям в зависимости от 
того, кто говорит.  Конкретный синтаксис неважен.

Один из совсем немногих языков, где это имеется — это JavaScript.
Дам пример на нем.

В этом языке у каждой функций имеется (составная) переменная arguments, а у 
arguments имеется часть callee.  Так вот, arguments.callee — это то, о чем я 
говорю.  В результате можно написать, скажем, анонимный рекурсивный факториал:

function(n) {return n<2 ? 1 : n*arguments.callee(n-1)}

и вызвать его можно так:

(function(n) {return n<2 ? 1 : n*arguments.callee(n-1)})(5)

(или передать кому-нибудь как значение, а вызывать буд

Re: FW: Рефал умер?

2017-08-04 Пенетрантность Boyko Bantchev
Здравствуйте, Александр!

> Вы не могли бы пояснить, что вы имеете ввиду под «цитированием
> себя и охватывающей функции при помощи … стандартной пары знаков
> или имён»?

Имею ввиду возможность, заложенную в языке, любой функции вызывать
себя через какое-то фиксированное, универсальное для этой роли имя.
Ну, или передавать свой адрес кому-то еще.  Подобно местоимениям «я»
или «себя»/«себе» в человеческой речи — человек говорит о себе, не
нуждаясь в имени.  Местоимение одно и то же, но относится к разным
людям в зависимости от того, кто говорит.  Конкретный синтаксис
неважен.

Один из совсем немногих языков, где это имеется — это JavaScript.
Дам пример на нем.

В этом языке у каждой функций имеется (составная) переменная
arguments, а у arguments имеется часть callee.  Так вот,
arguments.callee — это то, о чем я говорю.  В результате можно
написать, скажем, анонимный рекурсивный факториал:

function(n) {return n<2 ? 1 : n*arguments.callee(n-1)}

и вызвать его можно так:

(function(n) {return n<2 ? 1 : n*arguments.callee(n-1)})(5)

(или передать кому-нибудь как значение, а вызывать будет уже он сам).

Еще пример: обращение связанного списка функцией reverse.
reverse создает вложенную функцию с двумя аргументами (из первого
она накапливает результат во второй) и тут же ее вызывает.  Вложенная
функция рекурсивна и анонимна.

function reverse(x) {
  return (function(x,y) {
if (x) {
  var r = x
  x = x.next
  r.next = y
  return arguments.callee(x,r)
}
return y
  })(x,null)
}

(А список может быть, скажем, такой:

list = {data:1}
list = {data:2, next:list}
list = {data:3, next:list}
)

Иногда полезно подобным стандартным анонимным образом вызывать и
охватывающую функцию, возможно даже и ту, которая, в свою очередь,
ее охватывает — это позволяет уже взаимную анонимную рекурсию, но
таких средств ни в JavaScript, ни в других языках не видел.  (Сам
я такое свойство вложил в своем полуреализованном языке, но миру
от этого мало пользы :) )

Бойко


RE: FW: Рефал умер?

2017-08-03 Пенетрантность Александр Коновалов
Добрый день, Бойко!

Спасибо за интересные замечания!

Вы не могли бы пояснить, что вы имеете ввиду под «цитированием себя и 
охватывающей функции при помощи … стандартной пары знаков или имён»? Просто мне 
не очень понятна ваша терминология. И, если не сложно, приведите, пожалуйста, 
пример, используя какой-нибудь псевдокод (не обязательно Рефала).

Рантайм я писал достаточно давно, как и давно писал презентацию. Зачем писал 
эти избыточные конструкции? Мне они тогда нравились почему-то, потому и писал. 
В текущей версии исходников их уже нет:
https://github.com/bmstu-iu9/simple-refal/blob/master/src/srlib/refalrts.h
Руки дошли удалить их примерно год назад:
https://github.com/bmstu-iu9/simple-refal/commit/da7867

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

Здравствуйте, Александр!

> Именованные вложенные функции позволят программисту писать рекурсивные 
> и взаиморекурсивные функции ...

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

(А применима ли эта идея конкретно к вашей реализации я не знаю, так как следил 
посты поверхностно.)

Еще вметка.  Взглянув на ваши слайды, заметил несколько конструкций вида

typedef struct Node *NodePtr;
typedef struct Node { T data; Node* next; } Node;

На C++ нет потребности писать таким усложненным образом, поскольку

struct Node { T data;  Node* next; };

вполне хорошо работает.  (И вообще, везде в программе Node равнозначно struct 
Node — создавать синоним не приходится.)

Бойко Банчев


Re: FW: Рефал умер?

2017-08-03 Пенетрантность Boyko Bantchev
Здравствуйте, Александр!

> Именованные вложенные функции позволят программисту писать
> рекурсивные и взаиморекурсивные функции ...

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

(А применима ли эта идея конкретно к вашей реализации я не знаю,
так как следил посты поверхностно.)

Еще вметка.  Взглянув на ваши слайды, заметил несколько конструкций
вида

typedef struct Node *NodePtr;
typedef struct Node { T data; Node* next; } Node;

На C++ нет потребности писать таким усложненным образом, поскольку

struct Node { T data;  Node* next; };

вполне хорошо работает.  (И вообще, везде в программе Node
равнозначно struct Node — создавать синоним не приходится.)

Бойко Банчев


Re: FW: Рефал умер?

2017-08-01 Пенетрантность Arkady Klimov
кта его образу (что вижу, то и имею, ничего лишнего или
подразумеваемого).



> Вообще, я недавно начал смотреть лекции Абрамова по метавычислениям и
> задумался: а каким должен быть промышленный инструмент программиста для
> выполнения метавычислений? Подумалось, что это должен быть язык
> программирования и компилятор к нему, с хорошей поддержкой рефлексии
> (возможность как разобрать в рантайме AST любой функции, так и наоборот,
> её построить из AST и тут же вызвать), с возможностью интерпретации
> во время компиляции (как в C++14 constexpr), с возможностью сдампить
> набор функций в готовый для выполнения модуль. И если в такой среде
> реализовать специализатор как обычную библиотечную функцию, то вполне
> реализуются все три проекции Футамуры-Турчина. А потом вспомнил «пятикнижие
> Турчина» — описанный там язык и описанная там среда вполне подходят под это
> описание, разве что constexpr там нету.
>
 Да, надо "всего лишь" уметь извлекать функции из поля памяти в метакоде и
класть обратно. Между прочим, в рефале-6 для этого почти все есть, надо
только чуток модифицировать (и перекомпилировать) компилятор (чтобы
представление в метакоде оставалось где-то в конце выражения, являющегося
кодом языка сборки). Проблема лишь в том, чтобы договориться о формате
метакода, а на это не хватило духу.

>
>
> *Функциональные объекты этим условиям не удовлетворяют, они
> эктенсиональны: функцию можно вызвать, но нельзя препарировать, рассмотреть
> ее устройство.*
>
>
>
> Да, кстати. У меня (и у Скоробогатова в Refal’е-7) функциональные объекты
> сопоставляются с s-переменными.
>
Да, наверно это правильно. А функция TYPE их как-то выделяет?
А замыкание, это наверно уже не символ, а скобочный терм, да?

>
>
> *Но конечно, это не значит, что последователи не вправе делать по-своему,
> с опорой на новые знания и опыт. И может быть, особенности Рефала дадут
> возможность по новому увидеть и понять функциональные объекты.*
>
>
>
> Я разрабатывал (и разрабатываю) диалект Рефал-5λ (который сначала
> назывался Простой Рефал), ориентированный на промышленное программирование.
> Вложенные функции повышают продуктивность программиста — они есть.
> Необходимо расширение возможностей языка — библиотека функций не закрыта,
> можно написать свою функцию на Си++. Даже больше. Есть удобный синтаксис
> для написания таких функций — вставки кода на Си++ (
> https://github.com/bmstu-iu9/simple-refal/issues/11,
> https://github.com/bmstu-iu9/simple-refal/blob/master/src/sr
> lib/Library.sref). Т.е. не надо править и менять интерпретатор для
> написания ещё одной примитивной функции. Сейчас я работаю над унификацией
> с РЕФАЛом-5 (планирую сделать точное надмножество).
>
>
>
> *Что касается меня, как приложившего руку к созданию Рефала-6, могу только
> сказать, что в последние годы, уже лет 15, выступаю только как пользователь
> "своего" диалекта и пока вполне им доволен. Но это, конечно, не
> промышленное использование. Есть у Рефала-6 еще по-меньшей мере один
> активный пользователь - Игорь Щенков, и он время от времени высказывает
> претензии. Но к сожалению сил на них активно откликаться сейчас у меня
> очень мало. Се ля ви.*
>
>
>
> Когда я начинал программировать на Рефале, я начал с РЕФАЛа-5, пару
> программ написал на Рефале-6, а потом начал писать свой диалект J.
> Поэтому с идеями Рефала-6 знаком, программы читать могу, но программировать
> навыка нет, извините, что не стал вашей пользовательской базой. Кстати,
> завидую вам. Ваша пользовательская база по-меньшей мере в два раза больше
> моей J.
>

Пока я писал, в ветке произошла дискуссия о стилях написания кода. И хотя я
не хотел встревать, все-таки это дело вкуса во многом, но захотелось
высказаться по поводу длины имен переменных. Мне самому часто приходится
колебаться между длинным значимыми и однобуквенными (кстати поэтому я в
рефале-6 сохраняю бесточечную запись: e1, sA, ...). И в пользу коротких
есть следующий аргумент: Рефал, в отличии от классических императивных
языков является двумерным: предложение естественно пишется в строку, а
группа предложений в столбец. Но в предложении есть много чего: левая
часть, правая часть, доп.условия, и если имена длинные, то уж очень длинно
получается. А ломать строку в столбец - значит терять выразительные
возможности горизонтального измерения. Поэтому с однобуквенными именами
получатся нагляднее. Причем это особенно важно, когда левых частей много,
они длинные и мало отличаются. Тогда при записи их непосредственно друг под
другом лучше видны все отличия. Проиллюстрирую Вашим примером
https://github.com/bmstu-iu9/simple-refal/blob/master/doc/examples/inifile/inifile.sref
Там в конце есть вызов Reducе, в котором вложен функциональный блок с
шестью предложениями. Если бы их записать в шесть строк, с выравниванием,
думаю,

RE: FW: Рефал умер?

2017-07-26 Пенетрантность Александр Коновалов
" диалекта и пока вполне им доволен. Но это, конечно, не промышленное 
использование. Есть у Рефала-6 еще по-меньшей мере один активный пользователь - 
Игорь Щенков, и он время от времени высказывает претензии. Но к сожалению сил 
на них активно откликаться сейчас у меня очень мало. Се ля ви.

 

Когда я начинал программировать на Рефале, я начал с РЕФАЛа-5, пару программ 
написал на Рефале-6, а потом начал писать свой диалект :). Поэтому с идеями 
Рефала-6 знаком, программы читать могу, но программировать навыка нет, 
извините, что не стал вашей пользовательской базой. Кстати, завидую вам. Ваша 
пользовательская база по-меньшей мере в два раза больше моей :).

 

From: Arkady Klimov [mailto:arkady.kli...@gmail.com] 
Sent: Wednesday, July 26, 2017 2:23 PM
To: refal@botik.ru
Subject: Re: FW: Рефал умер?

 

Здравствуйте, Александр!

 

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

 

Правда, уже сейчас можно высказать и возражение. Есть основания полагать, что 
Рефал создавался Турчиным именно как язык первого порядка, и в этом была 
интенция автора. И другие особенности языка также были с этой интенцией 
согласованы, как-то: выражения с двусторонним доступом, явная активация, 
концепция "поля зрения", динамическая типизация (отсутствие статической 
типизации). Смысл в том, что любой объект, значение переменной, может быть 
рассмотрено во всех деталях, записано на бумаге, и при этом все, что будет 
видно, и только оно, может использоваться в вычислениях. Функциональные объекты 
этим условиям не удовлетворяют, они эктенсиональны: функцию можно вызвать, но 
нельзя препарировать, рассмотреть ее устройство. Это надлежит делать на 
метауровне, когда одной программе доступен код другой. И насколько я понимаю, 
попытки вводить абстракции, функции высших порядков и т.п. в базовый язык 
встречали сопротивление Турчина. Рефал-5 -- это максимум того, что он был готов 
допустить. Многие дополнительные возможности Рефала Плюс он уже считал 
излишними, кажется, даже динамические ящики.

 

Но конечно, это не значит, что последователи не вправе делать по-своему, с 
опорой на новые знания и опыт. И может быть, особенности Рефала дадут 
возможность по новому увидеть и понять функциональные объекты.

 

Что касается меня, как приложившего руку к созданию Рефала-6, могу только 
сказать, что в последние годы, уже лет 15, выступаю только как пользователь 
"своего" диалекта и пока вполне им доволен. Но это, конечно, не промышленное 
использование. Есть у Рефала-6 еще по-меньшей мере один активный пользователь - 
Игорь Щенков, и он время от времени высказывает претензии. Но к сожалению сил 
на них активно откликаться сейчас у меня очень мало. Се ля ви.

 

С уважением, 

Аркадий Климов,

с.н.с. ИППМ РАН,

+7(499)135-32-95
+7(916)072-81-48

 

25 июля 2017 г., 15:33 пользователь Александр Коновалов 
mailto:a.v.konovalo...@mail.ru> > написал:

В начале 2000-х годов язык Рефал ещё как-то развивался, выходили новые версии 
компиляторов: РЕФАЛ-5, Рефал-6, была некоторая активность на сайте 
http://wiki.botik.ru/Refaldevel/, был написан компилятор SCP4. Я читал старый 
архив рассылки refal <mailto:refal@botik.ru> @botik.ru, в нём тоже были 
обсуждения Рефала и не только (например, сравнивали его с Си++). Потом, 
практически синхронно со смертью Турчина, активность спала практически до нуля 
(архива рассылки refal-devel в сети не нашёл, судить не могу).

 

В текущей рассылке (судя по новому архиву) в основном рекламируются конференции 
по метавычислениям, выкладываются сканы старых архивных материалов и Сергей 
Михайлович Абрамов поздравляет с Новым Годом.

 

Я правильно понимаю ситуацию, что Рефал появился не от хорошей жизни: Турчину 
нужен был инструмент (формальный язык) для выражения идей метавычислений, 
суперкомпиляции, существовавшие тогда Фортран и Алгол для этого не подходили, а 
о Лиспе в СССР никто тогда не знал? И теперь, когда появились новые, 
современные функциональные языки программирования, для реализации идей 
суперкомпиляции стали применять уже их? Те же Юрий Климов и Илья Ключников свои 
суперкомпиляторы писали отнюдь не на Рефале. А язык Рефал остался в прошлом.

 

И то, чем я занимаюсь (https://github.com/bmstu-iu9/simple-refal (смотреть 
ветку refal-5-lambda),

Re: FW: Рефал умер?

2017-07-26 Пенетрантность Arkady Klimov
Здравствуйте, Александр!

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

Правда, уже сейчас можно высказать и возражение. Есть основания полагать,
что Рефал создавался Турчиным именно как язык первого порядка, и в этом
была интенция автора. И другие особенности языка также были с этой
интенцией согласованы, как-то: выражения с двусторонним доступом, явная
активация, концепция "поля зрения", динамическая типизация (отсутствие
статической типизации). Смысл в том, что любой объект, значение переменной,
может быть рассмотрено во всех деталях, записано на бумаге, и при этом все,
что будет видно, и только оно, может использоваться в вычислениях.
Функциональные объекты этим условиям не удовлетворяют, они эктенсиональны:
функцию можно вызвать, но нельзя препарировать, рассмотреть ее устройство.
Это надлежит делать на метауровне, когда одной программе доступен код
другой. И насколько я понимаю, попытки вводить абстракции, функции высших
порядков и т.п. в базовый язык встречали сопротивление Турчина. Рефал-5 --
это максимум того, что он был готов допустить. Многие дополнительные
возможности Рефала Плюс он уже считал излишними, кажется, даже динамические
ящики.

Но конечно, это не значит, что последователи не вправе делать по-своему, с
опорой на новые знания и опыт. И может быть, особенности Рефала дадут
возможность по новому увидеть и понять функциональные объекты.

Что касается меня, как приложившего руку к созданию Рефала-6, могу только
сказать, что в последние годы, уже лет 15, выступаю только как пользователь
"своего" диалекта и пока вполне им доволен. Но это, конечно, не
промышленное использование. Есть у Рефала-6 еще по-меньшей мере один
активный пользователь - Игорь Щенков, и он время от времени высказывает
претензии. Но к сожалению сил на них активно откликаться сейчас у меня
очень мало. Се ля ви.

С уважением,
Аркадий Климов,
*с.н.с. ИППМ РАН,*
*+7(499)135-32-95*
*+7(916)072-81-48*

25 июля 2017 г., 15:33 пользователь Александр Коновалов <
a.v.konovalo...@mail.ru> написал:

> В начале 2000-х годов язык Рефал ещё как-то развивался, выходили новые
> версии компиляторов: РЕФАЛ-5, Рефал-6, была некоторая активность на сайте
> http://wiki.botik.ru/Refaldevel/, был написан компилятор SCP4. Я читал
> старый архив рассылки refal@botik.ru, в нём тоже были обсуждения Рефала
> и не только (например, сравнивали его с Си++). Потом, практически синхронно
> со смертью Турчина, активность спала практически до нуля (архива рассылки
> refal-devel в сети не нашёл, судить не могу).
>
>
>
> В текущей рассылке (судя по новому архиву) в основном рекламируются
> конференции по метавычислениям, выкладываются сканы старых архивных
> материалов и Сергей Михайлович Абрамов поздравляет с Новым Годом.
>
>
>
> Я правильно понимаю ситуацию, что Рефал появился не от хорошей жизни:
> Турчину нужен был инструмент (формальный язык) для выражения идей
> метавычислений, суперкомпиляции, существовавшие тогда Фортран и Алгол для
> этого не подходили, а о Лиспе в СССР никто тогда не знал? И теперь, когда
> появились новые, современные функциональные языки программирования, для
> реализации идей суперкомпиляции стали применять уже их? Те же Юрий Климов
> и Илья Ключников свои суперкомпиляторы писали отнюдь не на Рефале. А язык
> Рефал остался в прошлом.
>
>
>
> И то, чем я занимаюсь (https://github.com/bmstu-iu9/simple-refal
> (смотреть ветку refal-5-lambda), https://github.com/Mazdaywik/mrefal) уже
> в проекте устарело на десятилетия? Не, своим хобби я заниматься продолжу,
> мне это интересно. Хоть и бесперспективно.
>
>
>
> --
>
> Коновалов Александр Владимирович, преподаватель
>
> кафедра ИУ9 «Теоретическая информатика и компьютерные технологии»
>
> МГТУ имени Н. Э. Баумана, Москва
>