Василий, не надо пошаговую прокрутку. Я неправильно посчитал скобки. Во входной 
строке их не 4, а 3, поэтому всё сходится: 3+1=4.

 

From: Василий Стеллецкий swi_AT_cnshb.ru <refal@botik.ru> 
Sent: Monday, December 14, 2020 4:58 PM
To: refal@botik.ru
Subject: Re: Запахи кода и антипаттерны в Рефале

 

Александр.
Действительно.
Еще раз, Большое спасибо.
PS Если хотите, могу прислать пошаговую прокрутку обоих вариантов...

 

-- 
С уважением,

-- 

Василий Стеллецкий

mailto:s...@cnshb.ru <mailto:sw...@narod.ru>   mailto:sw...@narod.ru    

 

 

 

14.12.2020, 16:38, "Александр Коновалов a.v.konovalov87_AT_mail.ru" 
<refal@botik.ru <mailto:refal@botik.ru> >:

Василий!

Разница тут принципиальная. В первом варианте стек был системный, программист 
писал рекурсивную функцию, явно со стеком не манипулировал. Поскольку 
программист за стек не отвечает, сломаться стек не может. Во втором случае — 
стеком явно управляет программист. И он может ошибиться, например, положить 
состояние на один стек и не положить на другой. Или снять состояние только с 
одного стека. В любом случае стеки рассинхронизируются. Или допустить ошибку в 
формате, перепутав стек с обрабатываемыми данными (например, перепутав tL и tR).

a =/0/k/Enum/ 'abc' (('de') 'f' ('gh') 'ij') 'k'.
Enum e1 = k/EndEnum/k/DoEnum/e1 /1/..
DoEnum s1 e2 sN = sN k/DoEnum/ e2 k/P1/sN..
      (e1)e2 sN = k/DoEnum-Wrap/ (k/DoEnum/ e1 sN.) e2.
      sN = sN
DoEnum-Wrap (e1 sN) e2 = (e1) k/DoEnum/ e2 sN.
EndEnum e1 sN = e1

И нету оборачивания скобки в рекурсивном решении.

Один шаг сэкономился на EndEnum, т.к. в последнем предложении мы и стеки 
отбрасываем, и счётчик. Ещё шаги экономятся на обработке скобок. Открывающая 
скобка в обоих вариантах требует одного шага. Закрывающая скобка — двух шагов: 
последнее предложение DoEnum, где она видит аргумент с пустой строкой и 
счётчиком и DoEnum-Wrap, которая выбрасывает вон скобку и продолжает цикл 
DoEnum. Но закрывающих скобок 4, должно сэкономиться 4 шага. И один на EndEnum. 
4+1≠4, где-то что-то я не учёл.

 

С уважением,
Александр Коновалов

 

From: Василий Стеллецкий swi_AT_cnshb.ru <refal@botik.ru 
<mailto:refal@botik.ru> >
Sent: Monday, December 14, 2020 4:05 PM
To: refal@botik.ru <mailto:refal@botik.ru> 
Subject: Re: Запахи кода и антипаттерны в Рефале

 

Александр!
Большое спасибо за подробный рассказ!
Но, то что в примере применили Вы - тоже самое: Справа стек.
Только просмотренную часть Вы не собирали в левой скобке, а сразу выводили за 
пределы функции...
Точнее стек получался из вызовов DoEnum-Wrap и скобок наизнанку ...
Еще раз, Большое спасибо!
P.S. А в этом варианте получился 31 шаг.
4 шага где-то сэкономили ;)

 

-- 
С уважением,

-- 

Василий Стеллецкий

mailto:s...@cnshb.ru <mailto:sw...@narod.ru>   mailto:sw...@narod.ru      

 

 

 

14.12.2020, 15:23, "Александр Коновалов a.v.konovalov87_AT_mail.ru" 
<refal@botik.ru <mailto:refal@botik.ru> >:

Василий!

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

Enum e1 = k/DoEnum/ /0/ ('$') e1 '$'.

* Формат: k/DoEnum/ sN (tL eS) eU tR
*   eS — просканированная часть
*   eU — непросканированная часть
*   tL — стек просканированных частей слева
*   tR — стек непросканированных частей справа

* символ просто переносим
DoEnum sN (tL eS) s1 eU tR = k/DoEnum/ k/P1/sN. (tL eS sN) eU tR.
* в скобочный терм спускаемся
       sN (tL eS) (e1) eU tR = k/DoEnum/ sN ((tL eS)) e1 (eU tR).
* термы кончились, но стек не пустой
       sN ((tL eS) e1) (eU tR) = k/DoEnum/ sN (tL eS (e1)) eU tR.
* термы кончились и стек тоже пустой — выход из цикла
       sN ('$' eS) '$' = eS

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

e1 (e2 (e3 ^ e4) e5) e6

где знак ^ означает позицию, вызов функции DoEnum будет иметь вид

k/DoEnum/ ((('$' e1) e2) e3) e4 (e5 (e6 '$')).

Т.е. незакрытые скобки перед ^ оказываются закрывающими, а неоткрытые после ^ — 
открывающими. А скобка между e3 и e4 служит указателем ^.

У Турчина в учебнике по Рефалу-5 предлагается немного другой способ кодирования 
стека, но он не менее страшный, чем этот. Сам Турчин, похоже, осознавал 
неестественность такого программирования, поэтому в комплекте с Рефалом-5 
поставляется препроцессор для сквозного просмотра скобок.

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

 

С уважением,
Александр Коновалов

 

From: Василий Стеллецкий swi_AT_cnshb.ru <refal@botik.ru 
<mailto:refal@botik.ru> >
Sent: Monday, December 14, 2020 1:52 PM
To: refal@botik.ru <mailto:refal@botik.ru> 
Subject: Re: Запахи кода и антипаттерны в Рефале

 

Добрый день, Александр!
Да, шагов поменьше!

a =/0/k/Enum/ 'abc' (('de') 'f' ('gh') 'ij') 'k'.

Enum e1 = k/EndEnum/k/DoEnum/e1 /1/..

DoEnum s1 e2 sN = sN k/DoEnum/ e2 k/P1/sN..

      (e1)e2 sN = k/DoEnum-Wrap/ k/DoEnum/ e1 sN. (e2).

      sN = sN

DoEnum-Wrap e1 sN (e2) = (e1) k/DoEnum/ e2 sN.

EndEnum e1 sN = e1

 

S:35 cc=0 M=1024

ПЗ: /0/ /1/ /2/ /3/ ( ( /4/ /5/ ) /6/ ( /7/ /8/ ) /9/ /10/ ) /11/

КОП:

 

Спасибо, понял что такое "выворачивание скобок" :)

 

-- 
С уважением,

-- 

Василий Стеллецкий

mailto:s...@cnshb.ru <mailto:sw...@narod.ru>   mailto:sw...@narod.ru      

 

 

 

14.12.2020, 13:25, "Александр Коновалов a.v.konovalov87_AT_mail.ru" 
<refal@botik.ru <mailto:refal@botik.ru> >:

Добрый день, Василий!

А если мы пишем для многопоточного Рефала, то статический ящик или копилка не 
подойдёт. Нужно использовать или динамический ящик, или передавать номер через 
параметр. Получится как-то так:

Enum e1 = k/DoEnum/e1 /0/.

DoEnum s1 e2 sN = sN k/DoEnum/ e2 k/P1/sN..
      (e1)e2 sN = k/DoEnum-Wrap/ k/DoEnum/ e1 sN. (e2).

DoEnum-Wrap e1 sN (e2) = (e1) k/DoEnum/ e2 sN.

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

 

С уважением,
Александр Коновалов

 

From: Василий Стеллецкий swi_AT_cnshb.ru <refal@botik.ru 
<mailto:refal@botik.ru> >
Sent: Monday, December 14, 2020 12:47 PM
To: refal@botik.ru <mailto:refal@botik.ru> 
Subject: Re: Запахи кода и антипаттерны в Рефале

 

Добрый день всем!

Я про задачку...
Ну, на мой взгляд не просто для понимания...
На других диалектах Рефала - да пожалуйста!
В этой задаче удобно использовать Ящики или Копилку.
Например с копилкой:

a =/0/k/Enum/ 'abc' (('de') 'f' ('gh') 'ij') 'k'.

Enum s1e2=k/Enum1/k/ВК/'n'..k/Enum/e2.

     (e1)e2=(k/Enum/e1.)k/Enum/e2.

     =

Enum1 =/1/k/ЗК/'n='/2/.

      sn=snk/ЗК/'n='k/P1/sn..

Результат:

S:62 cc=0 M=1024

ПЗ: /0/ /1/ /2/ /3/ ( ( /4/ /5/ ) /6/ ( /7/ /8/ ) /9/ /10/ ) /11/

КОП: ( 'n' '=' /12/ )

(первый /0/ в поле зрения не имеет отношения к задаче, это мой интерфейс)


 

 

-- 
С уважением,

-- 

Василий Стеллецкий

mailto:s...@cnshb.ru <mailto:sw...@narod.ru>   mailto:sw...@narod.ru    

 

 

 

14.12.2020, 10:47, "Александр Коновалов a.v.konovalov87_AT_mail.ru" 
<refal@botik.ru <mailto:refal@botik.ru> >:

Доброе утро всем!
 

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


К представлению объектных выражений этот приём (антиприём) не имеет отношение. 
Он, скорее, характерен для базисного Рефала (Рефала-2), в котором нет ничего 
подобного let-конструкциям (условия, перестройки, действия). И благодаря этому 
сквозному обходу исчезает нужда во вспомогательных функциях, можно обойтись 
одной.

Но, вообще этот приём уродлив, хоть и пропагандировался Турчиным.

 

 2. Боязнь копирования кусков выражений в разные «дочерние» функции.


А в Рефале-5 ещё и в условия.

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

А нет ли в Рефале Плюс другой боязни — боязни конкатенации?


Задача. Заменить в выражении все символы последовательными натуральными числами:

<Enum 'abc' (('de') 'f' ('gh') 'ij') 'k'> → 1 2 3 ((4 5) 6 (7 8) 9 10) 11

Решение на Рефале-5λ, эффективное (O(n)) и простое для понимания (на мой 
взгляд):

Enum {
  e.Expr
    = <DoEnum e.Expr 1> : e.Expr^ s.Num
    = e.Expr;
}

DoEnum {
  /* пусто */ s.Num = s.Num;

  s.X e.Expr s.Num = s.Num <DoEnum e.Expr <+1 s.Num>>;

  (e.Nested) e.Expr s.Num
    = <DoEnum e.Nested s.Num> : e.Nested^ s.Num^
    = (e.Nested) <DoEnum e.Expr s.Num>;
}

Конструкции = … : … в Enum и в последнем предложении DoEnum неявно 
транслируются в вызов вспомогательной функции. Знак ^ после имени переменной в 
образце означает, что она не повторная. Представление данных — плоское 
списковое, то самое с дорогим копированием и копеечной конкатенацией.

Как будет выглядеть O(n) решение в других диалектах Рефала?


С уважением,
Александр Коновалов



-----Original Message-----
From: Sergei M. Abramov abram_AT_botik.ru <refal@botik.ru 
<mailto:refal@botik.ru> >
Sent: Monday, December 14, 2020 4:27 AM
To: Александр Коновалов a.v.konovalov87_AT_mail.ru <refal@botik.ru 
<mailto:refal@botik.ru> >
Subject: Re: Запахи кода и антипаттерны в Рефале

День добрый, всем!
 

 А какие вы можете назвать запахи кода и антипаттерны, характерные для
 Рефала?


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

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

2. Боязнь копирования кусков выражений в разные "дочерние" функции.

Этим страдают многия языки. Например, в Эрланге целый культ на тему "стремись к 
хвостовой рекурсии!" и "пиши с аккумулятором, а потом выдай результат, навесив 
на него reverse (Который, видимо, у них написан на не Erlang-е)".

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

С уважением,

Абрамов С.М.
ab...@botik.ru <mailto:ab...@botik.ru> 
мобильный: +7(903)2928308
 

  • RE:... Александр Коновалов a . v . konovalov87_AT_mail . ru
    • ... Andrei Klimov andrei_AT_klimov . net
      • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
    • ... Василий Стеллецкий swi_AT_cnshb . ru
      • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
        • ... Василий Стеллецкий swi_AT_cnshb . ru
          • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
            • ... Василий Стеллецкий swi_AT_cnshb . ru
            • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
            • ... Василий Стеллецкий swi_AT_cnshb . ru
            • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
            • ... Arkady Klimov arkady . klimov_AT_gmail . com
            • ... nikolai . kondratiev_AT_gmail . com
            • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
            • ... Александр Коновалов a . v . konovalov87_AT_mail . ru

Ответить