Автор Тема: [Oberon 07/13] Семантика FOR  (Прочитано 18914 раз)

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #15 : Ноябрь 26, 2013, 07:16:50 pm »
for Count in List loop
    Put (Count);
end loop;
Разве в Аде есть форыч?   ???

Я думал это обычный for.
А что такое тут List?

Да уж, тут Валексей нам мозги запудрил ))) Вот оригинальный текст:
3.6.3 Цикл for

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

 Конструкция цикла for Ады аналогична конструкции цикла for, представленной в языке Паскаль.

 Существует несколько правил использования цикла for:
тип переменной-счетчика цикла for определяется типом указываемого диапазона значений счетчика, и должен быть дискретного типа, вещественные значения - недопустимы
счетчик не может быть модифицирован в теле цикла, другими словами - счетчик доступен только по чтению
область действия переменной-счетчика распространяется только на тело цикла

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

for счетчик in диапазон_значений_счетчика loop

    -- инструкции тела цикла

end loop;


for  Count in 1..20 loop
    Put (Count);
end loop;


 Возможен перебор значений диапазона в обратном порядке:

for счетчик in reverse диапазон_значений_счетчика loop

    -- инструкции тела цикла

end loop;


for Count in reverse 1..20 loop
    Put (Count);
end loop;


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

declare
    subtype List is Integer range 1..10;

begin
    for Count in List loop
        Put (Count);
    end loop;
end;


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

Тут List -- всего лишь подтип целого типа.
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: [Oberon 07/13] Семантика FOR
« Ответ #16 : Ноябрь 26, 2013, 07:36:15 pm »
Вообще где у нас форыч есть?
Знаю что в VB, Java, Lua, Python, PHP, JS, C#, C/C++ (через макросы только)

В Lua он работает через замыкание. Сделано универсально без лишних сущностей (for in просто принимает функцию)
В Java через через методы коллекции (глубже вшито в язык чем в Lua)

Оба варианта требуют серьезных изменений в языке.

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: [Oberon 07/13] Семантика FOR
« Ответ #17 : Ноябрь 26, 2013, 07:40:58 pm »
Вау! В 11'ых плюсах появился таки форыч: http://en.wikipedia.org/wiki/Foreach_loop#C.2B.2B
 :D

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #18 : Ноябрь 26, 2013, 08:11:10 pm »
Вообще где у нас форыч есть?
Знаю что в VB, Java, Lua, Python, PHP, JS, C#, C/C++ (через макросы только)
В С++98 std::for_each это не макрос, это просто функция.
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #19 : Ноябрь 26, 2013, 08:12:27 pm »
Вау! В 11'ых плюсах появился таки форыч: http://en.wikipedia.org/wiki/Foreach_loop#C.2B.2B
 :D
Причем заметь, обошлось без итераторов и "коллекций" вшитых в язык :-)
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #20 : Ноябрь 26, 2013, 08:18:13 pm »

Да уж, тут Валексей нам мозги запудрил ))) Вот оригинальный текст:
Во-первых не всего лишь. Это означает что цикл For из Ады бесполезен без её системы типов. А система типов в Аде по сложности тянет поболее чем на 16 страниц :-)

Во-вторых ты проигнорировал второй мой пример. Эти примеры НЕ идентичны.
Y = λf.(λx.f (x x)) (λx.f (x x))

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #21 : Ноябрь 26, 2013, 08:28:17 pm »

Да уж, тут Валексей нам мозги запудрил ))) Вот оригинальный текст:
Во-первых не всего лишь. Это означает что цикл For из Ады бесполезен без её системы типов. А система типов в Аде по сложности тянет поболее чем на 16 страниц :-)

Во-вторых ты проигнорировал второй мой пример. Эти примеры НЕ идентичны.

Второй пример -- это вот этот?
for Count in My_Array_Var'Range loop
    ...
end loop;
Так это по сути тоже самое, просто здесь мы явно указываем, что нам нужен диапазон индексов массива, а в случае с подтипом целого типа компилятор сам выводит, что нам нужен диапазон этого подтипа. Особой разницы нет -- и там и там диапазоны чисел...
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #22 : Ноябрь 26, 2013, 08:35:48 pm »

Да уж, тут Валексей нам мозги запудрил ))) Вот оригинальный текст:
Во-первых не всего лишь. Это означает что цикл For из Ады бесполезен без её системы типов. А система типов в Аде по сложности тянет поболее чем на 16 страниц :-)

Во-вторых ты проигнорировал второй мой пример. Эти примеры НЕ идентичны.

Второй пример -- это вот этот?
for Count in My_Array_Var'Range loop
    ...
end loop;
Так это по сути тоже самое, просто здесь мы явно указываем, что нам нужен диапазон индексов массива, а в случае с подтипом целого типа компилятор сам выводит, что нам нужен диапазон этого подтипа. Особой разницы нет -- и там и там диапазоны чисел...
Нет, разница есть. Массивы в Аде могут быть длины неизвестной на этапе компиляции.
Y = λf.(λx.f (x x)) (λx.f (x x))

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #23 : Ноябрь 26, 2013, 08:39:52 pm »
Разве в Аде есть форыч?   ???

Кстати, в той же вики пишется:
Ada 2012 has generalized loops to foreach loops on any kind of container (array, lists, maps...):
for Obj of X loop
   -- Work on Obj
end loop;
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #24 : Ноябрь 26, 2013, 08:46:32 pm »
Разве в Аде есть форыч?   ???

Кстати, в той же вики пишется:
Ada 2012 has generalized loops to foreach loops on any kind of container (array, lists, maps...):
for Obj of X loop
   -- Work on Obj
end loop;

Ну дык описанные мною выше конструкции - это по сути форыч образца 1983 года, тогда это представлялось вот так. Еще не было понимания как именно следует делать форыч, но было уже ясно что форыч штука много более правильная и безопасная для множества применений (но не для всех конечно, поэтому там есть и другие виды циклов), нежели обычный фор из паскаля, фортрана, или тем более while. Теперь же наконец выкатили уже современный, зрелый вариант.
Y = λf.(λx.f (x x)) (λx.f (x x))

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #25 : Ноябрь 27, 2013, 07:15:07 am »
Ну дык описанные мною выше конструкции - это по сути форыч образца 1983 года, тогда это представлялось вот так. Еще не было понимания как именно следует делать форыч, но было уже ясно что форыч штука много более правильная и безопасная для множества применений (но не для всех конечно, поэтому там есть и другие виды циклов), нежели обычный фор из паскаля, фортрана, или тем более while. Теперь же наконец выкатили уже современный, зрелый вариант.

for с итератором был ещё в языке CLU 1974 г.:
Цитата: http://ru.wikipedia.org/wiki/Клу
Итераторы

Одной из ключевых новаций языка стало введение абстракции управления — итератора. Идея итератора в том, чтобы обеспечить обобщённую реализацию доступа к элементам абстрактного типа данных вне зависимости от его параметризации и реализации. Реализация итератора полиморфного списка:
elems = iter (l:cvt) yields (t)
         for elt:t in rep$elements(l) do
           yield (elt)
         end
        end elems
Вызов такого итератора:
for i:int in lint$elems(l) do
  writeint (i)
end
Применение итератора позволяет избегать использование явных счётчиков цикла в условиях, когда заранее неизвестна конкретная реализация типа данных.
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

ddn

  • Jr. Member
  • **
  • Сообщений: 59
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #26 : Декабрь 03, 2013, 05:38:48 am »
Думал вбросить это еще в теме "форыч зло" http://oberspace.dyndns.org/index.php/topic,591.0.html, но там был уклон в структурность continue-break в циклах. А здесь будет самое то.



Оператор FOR зло уже потому что модифицирует пространство имен, превращая свой счетчик из VAR-переменной в IN-переменную в своем операторном параметре StatementSeq (даже при вызове в StatementSeq других процедур, счетчик не должен менятся), а после вызова FOR-оператора значение счетчика не определено языком и как бы не имеет права использоваться. А хороший оператор не должен никак менять пространство имен, и зря Вирт вернул этот нехороший FOR в Оберон-07. Поэтому у меня давно есть решение: FOR если и можно оставить, то только как спецпроцедуру, в чьем пространстве имен декларируется одно имя read only целого типа (а не импортируется как сейчас), а остальные идентификаторы globalIdent`i (i=1..N) импортируются в операторное тело StatementSeq как обычно (глобально).

То есть прежний вызов оператора FOR
ForStatement =
FOR ident ":=" Expr1 TO Expr2 [BY ConstExpr] DO
StatementSeq <* "(" ident {"," globalIdent`i} ")" *>
END.
превращается теперь в спецдекларацию процедуры identForProc:
ForProcDecl =
PROCEDURE identForProc FOR ident ":" identType [BY ConstExpr] DO
StatementSeq <* "(" ident {"," globalIdent`i} ")" *>
END identForProc.
а вызывается как обычная процедура:
identForProc(Expr1, Expr2 (* : <= identType *))где идентификатор identType - целый тип.
Хотя под вызовы FOR с разными (ident, ConstExpr, StatementSeq) придется декларировать как отдельные процедуры, но это будет правильно.

Делать ConstExpr внешним фактическим параметром, подобно Expr1 и Expr2, не следует, так как в Паскаль-языках нет объявления процедур с константными фактическими параметрами (будет нестандартная сигнатура), и как фактический параметр ConstExpr не мог бы тогда опускаться, подразумевая стандартное значение 1, а его значение 0 не давало бы ошибку при компиляции.
Но при желании, выражения Expr1 и Expr2, служащие фактическими безымянными параметрами, также можно убрать в декларацию:
PROCEDURE identForProc FOR<*IN*> ident ":" identType "=" Expr1 TO Expr2 [BY ConstExpr] DO
StatementSeq <* "(" ident {, globalIdent`i} ")" *>
END identForProc
Будет процедура без фактических параметров:
identForProc()

Помимо синтаксиса декларации, отличие FOR-процедуры от обычной процедуры состоит в многократном выполнении операторного тела StatementSeq при каждом вызове FOR-процедуры. При этом IN-переменная-счетчик ident в начале вызова инициируется значением Expr1, а между повторными выполнениями тела процедуры значение счетчика приращается на константную величину ConstExpr либо 1.

Все это можно описать и с помощью обычных процедур:
CONST
h = ConstExpr;
Check = 1 DIV h; (* h # 0 *)
...
PROCEDURE identForProc ((*IN*) i0, i1: identType);

VAR ident: identType;

PROCEDURE Stats (IN i: LONGINT);
BEGIN
StatementSeq (* (i, ... (* без h, i0 и i1 *)) *)
END;

BEGIN
ident := i0;
IF h>0 THEN
WHILE ident <= i1 DO
Stats(ident);
INC(ident, h)
END
ELSE
WHILE ident >= i1 DO
Stats(ident);
INC(ident, h)
END
END
END identForProc;
...
identForProc(Expr1, Expr2);
Приходиться делать два уровня вложенности, один для локальной переменной-счетчика, а второй для фиксации ее значения. Довольно громозко, и корректность конструкции должен проверять программист. Но поскольку, кроме Expr1, Expr2, ConstExpr и StatementSeq, прочее содержимое конструкции одинаково для всех FOR-процедур, то эти декларации можно сократить до предложеннего мною варианта спецпроцедуры.



Поскольку старый оператор FOR импортировал только те имена, что имеются в области видимости его вызова, вызов FOR-процедуры также можно разрешить только в той области видимости, где задекларирована сама эта FOR-процедура, т.е. идентификатор identForProc FOR-процедуры не должен экспортироваться во вложенные области видимости. Тогда мы получим почти аналог INLINE. Любой вызов FOR-процедуры можно будет заменить обратно на оператор FOR. При этом правда потребуется декларацию процедуры заменить на декларацию переменной-счетчика, и для каждого вызова FOR-оператора переменная-счетчик должна быть взята своя. Чистый INLINE был бы, если бы процедура не объявляла внутри себя никаких идентификаторов (кроме других вложенных INLINE процедур) и не имела бы именованных параметров (тогда ее декларация при INLINE просто отбрасывается), опять же при условии что вызовы такой процедуры идут только в той области видимости, где она была продекларирована.

Это условие необходимо хотя бы потому, что еще нужно учесть случай вложенных FOR-операторов. Ведь их операторные параметры StatementSeq имеют совпадающие области видимости за исключением того, что счетчик вложенного FOR как бы не виден в объемлющем его FOR (за вычетом области вложенного FOR). Значит FOR-процедуры, заменяющие эти вложенные операторы, дожны быть продекларированы внутри той же области видимости, но аналогично вложенными одна в другую. Декларативную область FOR-процедур для учета этой вложенности следует дополнить процедурным сектором для FOR-подпроцедур:

ForProcDecl =
PROCEDURE identForProc FOR ident ":" identType [BY ConstExpr]
{";" ForProcDecl`i}
DO
StatementSeq <* "(" ident {"," identForProc`i} {"," globalIdent`j} ")" *>
END identForProc.


У хорошего оператора должны быть только три синтаксических вида параметров: Designator, Expression и Statement (StatementSeq). Переменная-счетчик FOR-оператора теоретически тоже может быть любым составным именем, т.е. компонентой переменной, даже динамической, и даже импортироваться из другого модуля, но тогда ее изменения трудно контролировать. Поэтому счетчик FOR-оператора сделан строго ident. Я считаю, что таким (по синтаксису) параметрам место только в декларативной области.
Даже ConstExpression параметры в операторах идеологически подозрительны. Кроме FOR-оператора (необязательная секция BY), они были еще только в метках оператора CASE. Но уже в 07 версии Вирт их выпилил, заменив правда на более худший (усеченный) вариант: label = integer | string | ident. ConstExpression тоже должны быть только в декларациях.

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #27 : Декабрь 03, 2013, 06:26:51 am »
А здесь будет самое то.

А можно пример (кода) того, что получится в итоге?
А заводить переменную цикла тут же в FOR будет не проще, не?

ddn

  • Jr. Member
  • **
  • Сообщений: 59
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #28 : Декабрь 03, 2013, 11:14:14 am »
А можно пример (кода) того, что получится в итоге?
Вот например функция, вычисляющая детерминант матрицы:
PROCEDURE Det (IN A: ARRAY OF ARRAY OF REAL; (*IN*) n: INTEGER): REAL;
VAR
b: POINTER TO ARRAY OF BOOLEAN;
C: POINTER TO ARRAY OF ARRAY OF REAL;
d: REAL;
i, j, k, l: INTEGER;
BEGIN
ASSERT((LEN(A, 0) <= n) & (LEN(A, 1) <= n));
NEW(b, n); (* b[i] = FALSE *)
NEW(C, n, n);
FOR i := 0 TO n - 1 DO
FOR j := 0 TO n - 1 DO
C[i, j] := A[i, j]
END
END;
d := 1;
j := 0;
WHILE j < n DO
i := 0;
WHILE (i < n) & (b[i] OR (C[i, j] = 0)) DO
i := i + 1
END;
IF i = n THEN (* EXITIF.EXITWHILE *)
d := 0;
j := n - 1
ELSE (* ~b[i] & (C[i, j] # 0) *)
d := d * C[i, j];
(* C     b       j        l    *)
(* i:  FALSE  C[i, j]  C[i, l] *)
(* k:  FALSE  C[k, j]  C[k, l] *)
b[i] := TRUE;
FOR k := 0 TO n - 1 DO
IF ~b[k] THEN
FOR l := j + 1 TO n - 1 DO
C[k, l] := C[k, l] - C[k, j] * C[i, l] / C[i, j]
END
END
END;
FOR k := i + 1 TO n - 1 DO
IF ~b[k] THEN
C[k, j] := 0
END
END
(* C     b       j                       l                   *)
(* i:  TRUE   C[i, j]                 C[i, l]                *)
(* k:  FALSE     0     C[k, l] - C[k, j] * C[i, l] / C[i, j] *)
END;
INC(j)
END;
C := NIL;
b := NIL
;RETURN
d
END Det;
В ней 5 операторов FOR, причем две пары вложенных.

Поместив ее в модуль, можно проверить:
MODULE det;
IMPORT StdLog;
VAR a: ARRAY 2 OF ARRAY 2 OF REAL;
...
BEGIN
a[0, 0] := 3; a[0, 1] := 7;
a[1, 0] := 5; a[1, 1] := 11;
StdLog.Real(Det(a, 2)); (* -2.0 *)
a[0, 0] := 5; a[0, 1] := 5;
a[1, 0] := 9; a[1, 1] := 9;
StdLog.Real(Det(a, 2))  (*  0.0 *)
END det.

В результате замены операторов FOR на процедуры получим:
PROCEDURE Det (IN A: ARRAY OF ARRAY OF REAL; (*IN*) n: INTEGER): REAL;
VAR
b: POINTER TO ARRAY OF BOOLEAN;
C: POINTER TO ARRAY OF ARRAY OF REAL;
d: REAL;
i, j: INTEGER;

PROCEDURE For1 FOR i : INTEGER;
PROCEDURE For4 FOR j : INTEGER DO
C[i, j] := A[i, j]
END
DO
For4(0, n - 1)
END;

(* FOR i := 0 TO n - 1 DO
FOR j := 0 TO n - 1 DO
C[i, j] := A[i, j]
END
END;

For1(0, n - 1); *)

PROCEDURE For2 FOR k : INTEGER;
PROCEDURE For5 FOR l : INTEGER DO
C[k, l] := C[k, l] - C[k, j] * C[i, l] / C[i, j]
END
DO
IF ~b[k] THEN
For5(j + 1, n - 1)
END
END;

(* FOR k := 0 TO n - 1 DO
IF ~b[k] THEN
FOR l := j + 1 TO n - 1 DO
C[k, l] := C[k, l] - C[k, j] * C[i, l] / C[i, j]
END
END
END;

For2(0, n - 1); *)

PROCEDURE For3 FOR k : INTEGER DO
IF ~b[k] THEN
C[k, j] := 0
END
END;

(* FOR k := i + 1 TO n - 1 DO
IF ~b[k] THEN
C[k, j] := 0
END
END;

For3(i + 1, n - 1); *)

BEGIN
ASSERT((LEN(A, 0) <= n) & (LEN(A, 1) <= n));
NEW(b, n); (* b[i] = FALSE *)
NEW(C, n, n);
For1(1, n);
d := 1;
j := 0;
WHILE j < n DO
i := 0;
WHILE (i < n) & (b[i] OR (C[i, j] = 0)) DO
i := i + 1
END;
IF i = n THEN (* EXITIF.EXITWHILE *)
d := 0;
j := n - 1
ELSE (* ~b[i] & (C[i, j] # 0) *)
d := d * C[i, j];
(* C     b       j        l    *)
(* i:  FALSE  C[i, j]  C[i, l] *)
(* k:  FALSE  C[k, j]  C[k, l] *)
b[i] := TRUE;
For2(0, n - 1);
For3(i + 1, n - 1)
(* C     b       j                       l                   *)
(* i:  TRUE   C[i, j]                 C[i, l]                *)
(* k:  FALSE     0     C[k, l] - C[k, j] * C[i, l] / C[i, j] *)
END;
INC(j)
END;
C := NIL;
b := NIL
RETURN
d
END Det;
Если это покажется слишком сложным или трудным для восприятия, то FOR нужно выпилить вообще. Либо так, либо никак.


А заводить переменную цикла тут же в FOR будет не проще, не?
Будет методологически неправильней. Почему в операторном теле процедуры должны быть какие-то декларации?
В паскалевских ЯП декларативная область отделена от операторной. Иначе мы получим язык Дейкстры, где у каждого вызываемого оператора свое пространство имен. Операторы не должны вводить новых сущностей или менять свойства уже существующих, их дело работать с тем что уже есть. А если в теле процедуры в одном месте действуют одни сущности, в другом другие, или одна и та же используется с разным смыслом в разных местах, то это основание, чтобы вывести такие участки в подпроцедуры.

Wlad

  • Jr. Member
  • **
  • Сообщений: 91
    • Просмотр профиля
Re: [Oberon 07/13] Семантика FOR
« Ответ #29 : Декабрь 03, 2013, 12:57:06 pm »
... где у каждого вызываемого оператора свое пространство имен. Операторы не должны вводить новых сущностей или менять свойства уже существующих, их дело работать с тем что уже есть. А если в теле процедуры в одном месте действуют одни сущности, в другом другие, или одна и та же используется с разным смыслом в разных местах, то это основание, чтобы вывести такие участки в подпроцедуры.
Зависит. :)
Не надо однозначных оценок на уровне деклараций по организационным аспектам. Из каждого правила есть исключение (а есть области, где как раз одни исключения и работают :) ). Особенно, если затрагивается субъективное и неосмысливаемое на первый взгляд...

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