DRAKON.SU

Текущее время: Пятница, 22 Июнь, 2018 10:38

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 86 ]  На страницу Пред.  1, 2, 3, 4, 5  След.
Автор Сообщение
СообщениеДобавлено: Пятница, 08 Июнь, 2018 20:13 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 174
Владимир Ситников писал(а):
Код:
process atFloor( : #idle  : #start) {
    open -> openDoor(), set t, opened;
    opened, closeButton() or t >= Tdoor -> closeDoor(), close;
    close, closedDoor() -> decisionClosed( : #idle  : #start);
    close, blockedDoor() -> open;
}

По-моему, это сомнительная конструкция.
Получается, atFloor удивительным образом зависит от "переданных свыше" #idle, #start, при этом для самой "гиперфункции" atFloor что #idle что #start всё равно.

Автоматное (и предикатное) программирование от В.И. Шелехова это, прежде всего, средство моделирования и верификации. И спецификации там математические, с адаптацией в меру возможности быть похожим на языки программирования. Для процесса atFloor не заданы входные аргументы (они указываются перед ":"), а "#idle" и "#start" -- результат исполнения процесса (данные, возвращаемые процессами (в данном случае их нет), могут быть помечены множеством альтернативных "управленческих состояний" для дальнейшего продвижения по трассе исполнения). "Состояния" можно интерпретировать, в некоторой степени, в качестве неких гибких меток и goto.
Ранее в теме была ещё одна выдержка из публикации с процессом "Работа_часов_с_будильником", где есть метки-"состояния":
https://forum.drakon.su/viewtopic.php?f=142&t=6246&start=20#p101684
В контексте "бытового" программирования/моделирования такой процесс может быть задан в виде Р-схемы аля:
Вложение:
atfloor.png
atfloor.png [ 6.36 КБ | Просмотров: 271 ]

На схеме явно помечена лишь стартовая вершина "open" (мол остальные "состояния" внутренние, при потребности можем отразить и их). В случае события "blockedDoor()" переходим в начало, или при событии "closedDoor()" в зависимости от результата исполнения "decisionClosed()" осуществляется переход во внешний алгоритм или куда-то согласно методологии, где реализуются состояния "idle" и "start" (переход в одно из возможных состояний, где-то рядом будут и соответствующие схемы).
Или же примерно в таком стиле отражаются "функции-состояния" по Зюбину: мол схема выражает такую-то "функцию-состояние", которая может завершится переходами в такие-то "функции-состояния".

В данном случае семантика прохождения структур как у Закревского: ожидаем, пока не "исполнится" предикат, нет каких-то лишних (мешающих) "else"-частей для условий -- так поступать на Дракон-е проблематично (на чём уже неоднократно акцентировалось).
Владимир Ситников писал(а):
Конечно, бывают случаи (напр. упомянутый USB стек), когда моделировать нужно именно в виде автомата, но для тех случаев, по-моему, Дракон вообще не годится. Под словами "в виде автомата" я понимаю явное указание событий, состояний в "программе".

Конечно, манипулировать FSM в каком-то явном виде (и выбрать подходящий/удобный вид задача не простая, особенно в случае моделирования не только "программистами") на каждый чих утомительно, когда не уместно. В том и проблематика, что необходимо сочетать всяк разные методологии.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 08 Июнь, 2018 20:19 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 174
Владимир Ситников писал(а):
Если говорить про a-la suspend вариацию, то никакого lambda hell'а тут не возникает.
...

Под "лямбдами" я имел ввиду "блоки", возникающие в Kotlin (как и в других платформах/библиотеках) с помощью лямбд.

Пусть для идентификации события вместо вольного манипулирования глобальными переменными/процедурами (может быть и после каких-то yield) в виде:
"closeButton() or t >= Tdoor"

, необходимо использовать некие "suspend function" как:
"obj1.closeButton() or obj2.GetTime() >= Tdoor"

, т.е. как некое "вольное" применение без блокировок (в контексте выявления альтернатив ожидания в определенных специализированных местах).
PSV100 писал(а):
Т.е. сам концепт suspending functions ещё не обеспечивает методологическую успешность построения взаимодействующих процессов, за "прелесть" ещё нужно бороться...

Ну, прежде всего, в Kotlin, по-видимому, для своих типов ещё необходимо повозится с относительно низкоуровневыми средствами построения корутин -- к примеру, в Ada с task-ами (выше были ссылки) за "прелесть" уже поборолись, где эти task-и в т.ч. адаптированы для выявления вычислительных моделей в помощь использования формальных методов верификации (кроме базовых средств соблюдения семантики взаимодействия процессов).
Причины "универсальности" корутин в Kotlin понятны (удовлетворить потребности в имеющемся месиве API для java-инфраструктуры, как и в бесконечно возникающих новых).

Пусть для простоты используются какие-то имеющиеся типы с семантикой каналов. Тогда, если "одиночное" ожидание задаётся в виде функции "obj1.receive()", то для альтернативных событий привлекается функция в стиле "select { ... }", где внутри блока та же семантическая операция "receive" задаётся уже в виде иных функций в стиле "obj1.onReceive {...}", со своим блоком, в совокупности с другими блоками-событиями. Плюс в иерархии возникающих блоков могут быть прочие вложенные конструкции для указания исполнительного контекста и др. Т.е. многоуровневые конструкции (отчасти вынужденные) могут и затруднять понимание и т.п.
Средства "компактизации", по мотивам процесса atFloor выше, также необходимы. Если их не внедрять в базовых языковых конструкциях, то возникнут какие-то "макросы".


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 08 Июнь, 2018 20:24 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
PSV100 писал(а):
Для процесса atFloor не заданы входные аргументы (они указываются перед ":"), а "#idle" и "#start" -- результат исполнения процесса (данные, возвращаемые процессами (в данном случае их нет), могут быть помечены множеством альтернативных "управленческих состояний" для дальнейшего продвижения по трассе исполнения). "Состояния" можно интерпретировать, в некоторой степени, в качестве неких гибких меток и goto.


Я понимаю, что #idle и #start это что-то типа меток, куда должно перейти управление в случае завершения atFloor.
Мне не нравится то, что для самого алгоритма atFloor метки #idle и #start являются чужеродными.
И крайне некрасиво выглядит то, что по сути мы передаём метки #idle #start в atFloor только для того, чтобы передать эти метки в decisionClosed.

Если в исходный автомат добавится состояние (например, #startASAP), то его, возможно, придётся снова пробрасывать через atFloor, decisionClosed.
Выглядит это крайне сомнительно.
Я не про промежуточные состояния, а именно про idle/start.

Возможно, это там сама "гиперфункция atFloor" неудачно составлена и не следовало в ней смешивать понятия "закрытия дверей" и "решение о поездке". Но, раз уж она есть, то считаем, что это state of the art вариант реализации алгоритма лифта в предлагаемой нотации.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 10 Июнь, 2018 00:00 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
PSV100 писал(а):
[Пусть для простоты используются какие-то имеющиеся типы с семантикой каналов. Тогда, если "одиночное" ожидание задаётся в виде функции "obj1.receive()", то для альтернативных событий привлекается функция в стиле "select { ... }", где внутри блока та же семантическая операция "receive" задаётся уже в виде иных функций в стиле "obj1.onReceive {...}", со своим блоком, в совокупности с другими блоками-событиями. Плюс в иерархии возникающих блоков могут быть прочие вложенные конструкции для указания исполнительного контекста и др. Т.е. многоуровневые конструкции (отчасти вынужденные) могут и затруднять понимание и т.п.

Вы либо что-то путаете, либо недоговариваете.

Пример с select ... onReceive относится не к "альтернативным событиям ожидания у одного FSM". select .. onReceive было примером ожидания событий, которые могут прийти к двум разным FSM.

Приведёте пример, где реально нужно ожидать сообщения для двух разных FSM? Иначе получается, корутины и Шелехова/Закревского/Зюбина вы рассматриваете для совсем разных задач.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 12 Июнь, 2018 18:37 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 174
Владимир Ситников писал(а):
PSV100 писал(а):
Пусть для простоты используются какие-то имеющиеся типы с семантикой каналов. Тогда, если "одиночное" ожидание задаётся в виде функции "obj1.receive()", то для альтернативных событий привлекается функция в стиле "select { ... }", где внутри блока та же семантическая операция "receive" задаётся уже в виде иных функций в стиле "obj1.onReceive {...}", со своим блоком, в совокупности с другими блоками-событиями. Плюс в иерархии возникающих блоков могут быть прочие вложенные конструкции для указания исполнительного контекста и др. Т.е. многоуровневые конструкции (отчасти вынужденные) могут и затруднять понимание и т.п.

Вы либо что-то путаете, либо недоговариваете.

Пример с select ... onReceive относится не к "альтернативным событиям ожидания у одного FSM". select .. onReceive было примером ожидания событий, которые могут прийти к двум разным FSM.

Действительно, в случае применения функции аля select и соответствующих блоков-лямбд возникает композиция FSM, где каждая FSM ожидает событие. Такой взгляд на складывающеюся алгоритмическую систему есть условно "низкоуровневый", моделирование "в малом". При взгляде на моделирование "в большом" функция select в Kotlin есть продукт подражания одноименному оператору в Go при манипулировании каналами взаимодействия (как и функция "go", запускающая процессы, как и сами типы-каналы и пр.):
https://gobyexample.com/select

Такой паттерн взаимодействия процессов широко известен и является "классикой" (и название функции, фактически, аля стандарт, хотя возможны вариации вида "choose" и т.п.). В основе -- исчисление Communicating Sequential Processes (CSP) от товарища Hoare. Если не ошибаюсь, среди специализированных для CSP "высокоуровневых" языков пионером когда-то был Occam:
https://ru.wikipedia.org/wiki/Occam

, где на wiki-странице наглядно и кратко видна базовая суть (вместо исходной объёмной "математики"), для альтернативного ожидания используется оператор "ALT".
Недетерминизм и альтернативный выбор присутствуют в различных исчислениях или алгебрах процессов. Как и имеются всякие вариации оператора "select". Напр. в Ada (организация "рандеву" между процессами):
https://en.wikibooks.org/wiki/Ada_Progr ... ctive_Wait

, так и в виде библиотечных средств (API в виде комбинаторных функций над спецтипами), "классика" (которой подражают) есть Concurrent ML:
https://ru.wikipedia.org/wiki/Concurrent_ML

и вариации, напр., для истинно асинхронных процессов (со своими потоками):
Composable Asynchronous Events

или же альтернативный выбор в стиле функций по мотивам классической select в Unix-ах:
https://en.wikipedia.org/wiki/Select_(Unix)

В Kotlin с помощью типов-каналов и функций по мотивам "select" (процесс, использующий подобную функцию, выполняет альтернативный выбор-ожидание) осуществляется эмуляция CSP (в результате чего возникает некая композиция suspend-функций, "низкоуровневых" FSM), подражая реализации этого исчисления в Go согласно тренду в мейнстриме.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 12 Июнь, 2018 18:50 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 174
Владимир Ситников писал(а):
Приведёте пример, где реально нужно ожидать сообщения для двух разных FSM? Иначе получается, корутины и Шелехова/Закревского/Зюбина вы рассматриваете для совсем разных задач.

Откровенно говоря, всё-таки непонятно, что именно вы имеете ввиду. Прежде всего, как отмечено выше, есть потребность в альтернативе ожидания. В каких-то случаях удобнее использовать корутины с "ожиданиями". В иных случаях удобнее операции аля "select", или "ожидание" в корутине может быть на подобной операции, может быть с особой политикой обработки каналов, к примеру, как аля "select_rr" -- с "round robin" -- сработавшие каналы улетают в конец списка/массива для последующих попыток ожидания, и т.п.

На всякий случай, результаты Шелехова, Закревского, Зюбина направлены на моделирование процессов. У Зюбина, в частности, хорошо расписана "математика" (ранее по ссылкам в теме) для перехода от "низкоуровневого" представления автомата на основе понимания состояния как значения ячеек-регистров, через понимание состояния как совокупности значений переменных к "верхнеуровневому" представлению автомата как исполнимому полиморфному процессу (есть понятийные аналоги, к примеру "mode automata"). Интуитивно, без буквоедства (математику можно уточнить при потребности и она разная), понимание процесса и FSM в таком разрезе есть эквивалентные, в т.ч. возможна и вариация -- "активный" ли или "пассивный" процесс/автомат. И то же исчисление CSP, если необходимо, вполне может "уживаться" в применении как к автоматам, так и процессам (фактически, CSP и ему подобные есть средства для моделирования/оценки политики организации действий), и какие-то корутины/процессы для внутреннего общения не обязательно могут использовать какие-то специальные каналы -- те же глобальные переменные/объекты есть виртуальные каналы связи.

Как бы там ни было, у Шелехова, Закревского, Зюбина, да и Шалыто на борту есть средства как и для альтернативного ожидания событий, так и для параллельной композиции автоматов/процессов (где-то применяется аналог композиционного оператора PAR как в Occam, что эквивалентно понятию параллельных состояний/автоматов, где-то "ручной" пуск/останов, где-то операции дивергенции/конвергенции потоков управления). Параллельная композиция и есть способ "ожидать сообщения для двух разных FSM" и более.

В том числе возможна условно единственная точка ожидания событий (с альтернативами) одновременно для разных FSM. В контексте "классического" (аля табличного) представления автоматов обычно используется иерархия состояний/машин, где события в "супер-состоянии" приводят к "глобальным" переходам с прекращением работы внутренних (параллельных) состояний, как в отмеченном вами mbeddr:
https://forum.drakon.su/viewtopic.php?f=143&t=6160#p100900

Или вот техника не только с композиционными состояниями, но и с композицией машин для раздельного моделирования (с оптимизацией использования переменных и др.):
Beyond Event Handlers: Programming Wireless Sensors with Attributed State Machines

Ниже пример построения иерархии автоматов уже поближе к представлению их как процессов (в рамках той же предметки, но все методики моделирования универсальны):
High-Level Application Development is Realistic for Wireless Sensor Networks

В статейке выше -- расширение для Си (по мотивам Esterel и др.). Внутренние анонимные процессы-автоматы задаются через оператор параллельной композиции "[... || ...]". "Именные" процессы задаются в форме явных иерархических "машин состояний", "вытеснение" процессов происходит через переходы в "состояниях", плюс механизм прерывания "try/catch + raise" на условных сигналах (но это не "исключения" как в С++).
В данном случае параллельные процессы являются корутинами в рамках кооперативной многозадачности (с оператором yield для явного переключения контекста, с использованием аля "suspend"-функций).

И статейка, где подобные корутины задаются уже как максимально "классические функции":
Predictable Multithreading of Embedded Applications Using PRET-C

, где композиция процессов (в виде обычных С-функций) задаётся через оператор PAR, "вытеснение" -- в виде оператора "abort ... when ..." (эмуляция общего автоматного состояния), отчасти напоминающий такой оператор из самого текстового языка Esterel.
Кстати, такой подход и демонстрирует то, что "общие события" над алгоритмами должны быть связаны либо с их "вытеснением", т.е. переходами/прекращением работы, либо с иными какими-то действиями, не приводящими к косякам работы над общими объектами (кроме "вытеснения" (с действиями при глобальных переходах) могут быть операторы приостановки процессов, указания "сброса", т.е. команды "работать с начала", как "шаг" или "переход в себя" в контексте общего ("супер") автоматного состояния).

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 12 Июнь, 2018 19:01 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 174
Владимир Ситников писал(а):
Я понимаю, что #idle и #start это что-то типа меток, куда должно перейти управление в случае завершения atFloor.
Мне не нравится то, что для самого алгоритма atFloor метки #idle и #start являются чужеродными.
И крайне некрасиво выглядит то, что по сути мы передаём метки #idle #start в atFloor только для того, чтобы передать эти метки в decisionClosed.

Если в исходный автомат добавится состояние (например, #startASAP), то его, возможно, придётся снова пробрасывать через atFloor, decisionClosed.
Выглядит это крайне сомнительно.
Я не про промежуточные состояния, а именно про idle/start.

Проблематика интерфейсов процессов в такой методологии идентична аналогичным проблемам в интерфейсах функций в любых распространённых языках моделирования/программирования. Метки, вроде как, имеют локальный характер. Т.е. некий процесс, подобный atFloor, можно интерпретировать как-то так в другой нотации:
Код:
process atFloor(x: int) -> [#1(a: int, b: int), #2(c: int)] {
    ...
}

, где имеется входной аргумент "х" и как результат возможны два варианта исхода -- альтернативных (поэтому используются скобки "[...]" как набор или множество (для выбора) вместо "(...)" как кортеж). Каждый вариант результата помечен метками (при реализации процесса эти метки могут быть задействованы для выхода). Т.е. результат похож на некий алгебраический тип данных, но кроме состояния данных используется и состояние процесса.
В исходном процессе atFloor нет ни входных, ни выходных данных, и обозначены два результирующих состояния трассы выполнения. Метки при вызове процесса могут быть заданы свои в конкретном месте, как указание на дальнейшие ветки продолжения работы. Если в интерфейсе процесса появится третье состояние или возникнут иные изменения в ветках -- потребность в "рефакторинге", как и везде в подобных случаях.
Методика имеет достоинства и недостатки, т.е. свои особенности. В общем случае вложенные композиции как decisionClosed в atFloor неизбежны -- если не применять вложенные (иерархические) автоматы/состояния/процессы, то возможен "взрыв состояний".


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 12 Июнь, 2018 20:56 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
PSV100 писал(а):
Действительно, в случае применения функции аля select и соответствующих блоков-лямбд возникает композиция FSM, где каждая FSM ожидает событие. Такой взгляд на складывающеюся алгоритмическую систему есть условно "низкоуровневый", моделирование "в малом". При взгляде на моделирование "в большом" функция select в Kotlin есть продукт подражания одноименному оператору в Go при манипулировании каналами взаимодействия (как и функция "go", запускающая процессы, как и сами типы-каналы и пр.):
https://gobyexample.com/select


Давайте остановимся на том, что select в Kotlin'е это именно подражание Go-каналам? Я к тому, что вы крайне странно упомянули слова "lambda-hell", хотя при этом точно такую же конструкцию в Ada почему-то вы таким термином не называете. Давайте уж назовём do-end-hell?

Я хочу обратить внимание на то, что Kotlin coroutines != select.

Иными словами, можно вообще не использовать select/onReceive и всё равно пользоваться coroutine'ами.

И ещё момент: в отличие от Go/Ada и т.п., select неявляется ключевым словом языка Kotlin.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 12 Июнь, 2018 22:38 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
PSV100 писал(а):
Откровенно говоря, всё-таки непонятно, что именно вы имеете ввиду

То, что Kotlin coroutines (не частный случай в виде select, а механизм suspend functions в целом) гораздо более выразительный механизм, чем упомянутый пример atFloor.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Июнь, 2018 19:40 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 174
Владимир Ситников писал(а):
Давайте остановимся на том, что select в Kotlin'е это именно подражание Go-каналам? Я к тому, что вы крайне странно упомянули слова "lambda-hell", хотя при этом точно такую же конструкцию в Ada почему-то вы таким термином не называете. Давайте уж назовём do-end-hell?

Да пожалуйста, называйте. "Блок-hell", скорее всего, ещё самый "безобидный" hell на фоне в целом "адского программирования".

А конструкция select в Ada не точно такая же, как функция select в Kotlin. В Ada это языковый управляющий оператор, похожий по стилю на switch/case...of/match...with и т.п., для альтернативного выбора события в контексте процесса.

В Kotlin может быть Go не подражают (те же альтернативы событий есть понятие универсальное, включая и в теориях), но во всяком случае в док-ах постоянно имеется сопоставление с языковыми возможностями Go, и тем самым возникает демонстрация обеспечения "вычислительной мощности" (по понятным маркетинговым причинам), а то и более.
Такой код похож на оператор select в Go:
Код:
suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
    select<Unit> {
        fizz.onReceive { value ->
            println("fizz -> '$value'")
        }
        buzz.onReceive { value ->
            println("buzz -> '$value'")
        }
    }
}

А такой -- уже из разряда "а то и более":
Код:
fun asyncString(time: Int) = async {
    delay(time.toLong())
    "Waited for $time ms"
}

fun asyncStringsList(): List<Deferred<String>> {
    val random = Random(3)
    return List(12) { asyncString(random.nextInt(1000)) }
}

fun main(args: Array<String>) = runBlocking<Unit> {
    val list = asyncStringsList()
    val result = select<String> {
        list.withIndex().forEach { (index, deferred) ->
            deferred.onAwait { answer ->
                "Deferred $index produced answer '$answer'"
            }
        }
    }
    println(result)
    val countActive = list.count { it.isActive }
    println("$countActive coroutines are still active")
}

Если в Ada/Go оператор select есть конкретная алгоритмическая точка ожидания событий от смежных процессов (и в первом примере selectFizzBuzz применение функции select семантически примерно идентично), то функция select в Kotlin в общем случае есть нечто вроде наблюдательной секции -- сначала ещё исполняется лямбда-аргумент (после "входа" в точку ожидания и перед началом самого акта ожидания), и затем выполняется ожидание "привета" от каких-то suspend-функций, "установивших контакт" с select (и "знающих", как это делать).
Речь не о том, мол хорошо или плохо -- такова гибкая особенность функции select, которую необходимо учитывать при переводе на технологический моделецентричный язык (который может быть и как "устный в голове", так и формальный).
Владимир Ситников писал(а):
И ещё момент: в отличие от Go/Ada и т.п., select неявляется ключевым словом языка Kotlin

В итоге есть и последствия в виде вынужденного дублирования функционала как "await -> onAwait", "receive -> onReceive" и т.д. Причём в случае применения вариаций функции select как whileSelect лямбды, передаваемые "On-функциям", приобретают другую семантику или иной характер (их результат уже управляет циклом).
И для своих прикладных алгоритмов в случае взаимодействия с функцией аля select напрямую необходимо ещё разобраться с API и принципами построения операций (ожидания, возобновления, с конкретикой концепции "билдеров" для нужных типов, исполняемого контекста и т.д.). Отсюда и возникает потребность в стандартных типах-посредниках как те же "каналы".
В целом возникает эффект языков в стиле Ruby, где один и тот же функционал можно выразить десятками способов. Тот же Go имеет популярность не в последнюю очередь из-за своей условной простоты (сложность -- мера неоднородности).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Июнь, 2018 19:55 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 174
Владимир Ситников писал(а):
PSV100 писал(а):
Откровенно говоря, всё-таки непонятно, что именно вы имеете ввиду

То, что Kotlin coroutines (не частный случай в виде select, а механизм suspend functions в целом) гораздо более выразительный механизм, чем упомянутый пример atFloor.

Т.е. вы об этом:
Владимир Ситников писал(а):
Код:
process atFloor( : #idle  : #start) {
    open -> openDoor(), set t, opened;
    opened, closeButton() or t >= Tdoor -> closeDoor(), close;
    close, closedDoor() -> decisionClosed( : #idle  : #start);
    close, blockedDoor() -> open;
}

По-моему, это сомнительная конструкция.
Получается, atFloor удивительным образом зависит от "переданных свыше" #idle, #start, при этом для самой "гиперфункции" atFloor что #idle что #start всё равно.

Если говорить про a-la suspend вариацию, то никакого lambda hell'а тут не возникает.
Код:
// pre: стоим на этаже с открытыми дверями
// post: поймали добычу, закрыли дверь
suspend atFloor() {
    while(true) { // если поменять на for(i in 1..3), то будет 3 попытки закрыть дверь
        openDoor();
        set t;
        while (!(closeButton() or t)) {
            yield; /* ждёмс */
        }
        closeDoor();
        while(!blockedDoor()) {
            if (closedDoor()) {
                return; // дело сделано, можно принимать решение куда ехать
            }
            yield; /* ждёмс */
        }
    }
    throw new IllegalStateException("лифт сломался, идите пешком")
}


И для полноты картины выше была и Р-схемка:
Изображение

Насчёт выразительности самого механизма suspend functions. Вы для примера использовали функцию yield в совокупности с типовыми управляющими операторами. В иных случаях встретится код на каком-нибудь аля "Reactive Streams API", в итоге вроде и язык один и тот же вместе с тем же механизмом suspend functions, но возникает существенный диалект, с которым нужно и существенно разбираться, чтобы понять модель вычислений. Т.е. выразительность как таковой самой концепции блокируемых/приостанавливаемых операций где-то сбоку, прежде всего, важно семантическое содержательное, предметное наполнение.

Насчёт выразительности механизма, на котором реализован atFloor. "Метки", фактически, есть аналог return. Язык спецификаций, кроме альтернатив (как в примере) и рекурсий, имеет и явные последовательности, и параллельную композицию и пр. Конечно есть особенности и ограничения, в отличие от Kotlin/Java это язык моделей для перехода к формальным методам верификации или представлению моделей в другом виде (автоматизированно извлечь модель из кода на том же Kotlin -- в общем, результаты как и на Java, только вид сбоку).

Конечно, хорошо, когда на борту имеется удобный технологический язык конечной реализации (аля тот же Kotlin). И понятно удобство, как бы, последовательного (с паузами/переключениями) постепенного перемещения по алгоритмической трассе (с возвратами, если нужно), на которое, по-видимому, вы постоянно акцентируете.
Но автоматные спецификации есть универсальный способ алгоритмического представления для разных требований "выразительности". Имея их, ими можно вертеть с разных сторон, выражая задание трасс исполнения (не обязательно всей системы, это может быть некий протокол о намерениях в разрезе определенного аспекта) для уточнения или объяснения, проверок и верификации, для генераций тестов или/и имитационных моделей, для спецификаций будущих реализаций (может быть распределенных, на разных платформах) и пр. И не только в линеаризованной форме (в стиле кода atFloor на Kotlin выше), но и в каком-то свёрнутом виде (конечно, в случае реальной линейности трассы нет потребности в каких-то размашистых/развесистых конструкций для альтернатив), в том числе и в табличной форме, напр.:
Вложение:

Кроме текста, понимая вычислительную модель, Р-схему выше можно заменить на алгоритмическую. Т.е. дуги с предикатами как "ожидание" вида "closeButton() or t" заменяются циклами или чем там необходимо при конкретике на платформе (с дополнительным функционалом, с "suspend"-функциями если нужно). В результате исходную спецификацию можно соотнести с конечной реализацией. Или же сопоставить спецификации (реализации) смежных функций/автоматов (функцию atFloor и с чем она взаимодействует), вплоть до соотношения точек-"состояний" (вершин), или раскрыть отдельно протокол упорядоченности действий (производство/потребление данных/сигналов) и т.п. Или же воспользоваться циклограммами, как в ГрафКонт ("адаптивные расписания" выше в теме) для отражения некоторой совокупности процессов, необязательно именно во временных количественных оценках (они возникают в соответствующих предметках) -- хотя бы отразить упорядоченность -- возникающие следование, параллельности, дивергенции/конвергенции потоков, как здесь (рисунок внизу сообщения):
https://forum.drakon.su/viewtopic.php?p=93258#p93285

В общем, критерии "выразительности" разнообразны и очень таки.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Июнь, 2018 23:49 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
PSV100 писал(а):
Но автоматные спецификации есть универсальный способ алгоритмического представления для разных требований "выразительности". Имея их, ими можно вертеть с разных сторон, выражая задание трасс исполнения (не обязательно всей системы, это может быть некий протокол о намерениях в разрезе определенного аспекта) для уточнения или объяснения, проверок и верификации, для генераций тестов или/и имитационных моделей, для спецификаций будущих реализаций (может быть распределенных, на разных платформах) и пр. И не только в линеаризованной форме (в стиле кода atFloor на Kotlin выше),

И? Что это значит?
Значит, что нужно использовать формализм в духе atFloor? Нет.
Значит, что в бытовом программировании нужно использовать формализм в духе atFloor? Вовсе нет.

Я аналогичный пример приведу: язык ассемблера это универсальный способ алгоритмического представления разных программ для процессора Intel Core. Имея программу на этом языке можно вертеть её с разных сторон и так далее.

Значит ли это, что нужно всем пропагандировать ассемблер? Разумеется, нет.

Так и с atFloor. По-моему, это маргинальный подход. На нём можно писать только в FSM-callback стиле, и простую программу "светофора" написать невозможно. Нужно выдумывать состояния и тому подобное.

PSV100 писал(а):
И понятно удобство, как бы, последовательного (с паузами/переключениями) постепенного перемещения по алгоритмической трассе (с возвратами, если нужно), на которое, по-видимому, вы постоянно акцентируете.

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

В atFloor такой стиль невозможен.
В редакторе Тышова есть реверанс в подобную сторону: то ли у схемы, то ли у листа можно указывать "режим трансляции", который влияет на результирующий код (1 действие==1 состояние FSM, 1 ветка == 1 состояние FSM и тому подобное)

В Kotlin'е аналогично: добавили suspend модификатор -- функция компилируется в FSM. Не добавили -- компилируется в обычный код.

PSV100 писал(а):
Вы для примера использовали функцию yield в совокупности с типовыми управляющими операторами. В иных случаях встретится код на каком-нибудь аля "Reactive Streams API", в итоге вроде и язык один и тот же вместе с тем же механизмом suspend functions, но возникает существенный диалект, с которым нужно и существенно разбираться, чтобы понять модель вычислений. Т.е. выразительность как таковой самой концепции блокируемых/приостанавливаемых операций где-то сбоку, прежде всего, важно семантическое содержательное, предметное наполнение.

Не соглашусь. Выразительность концепции suspend functions позволяет создать функцию yield, которая приводит к "приостановке выполнения", и которая при этом правильно работает с обычными языковыми конструкциями if/for/try.
Да, в одной задаче может удобнее быть остановка выполнения командой yield, в другой задаче может оказаться удобнее a-la Reactive, в третьей задаче может удобно создать функцию, которая генерирует значения (ну, которая как бы бесконечно выполняет return, но после каждого возвращённого значения она приостанавливается).
Да, может потребоваться "въезжать" в предметное наполнение, но тратить время на понимание стиля нового для вас кода придётся в любом случае.

Та же самая "гиперфункция" atFloor. Она встречается только в одном конкретном проекте. Хоть так, хоть сяк придётся тратить время на понимание происходящего. Если в проекте сделали самопальную функцию yield, то, да, первый раз она может удивить. Но это не значит, что она ставит читателя в тупик на неделю.

Само же написание подобных функций как раз и становится возможным благодаря suspend functions.

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

С atFloor так невозможно.
В Дракон-схемах вопрос "семантики результирующего FSM" тоже не проработан.

=====


На тему configurable semantics in FSM есть исследование и рабочая интеграция с С кодом: https://github.com/z9luo/BSML-mbeddr
Вполне может быть, что семантика состояний должна настраиваться по удобству конкретного алгоритма.
К слову, в той статье один из режимов был syntactic big-step maximality. Т.е. когда "стабильные" состояния FSM размечаются руками программиста, и система выполняет переходы до тех пор, пока не дойдёт до стабильного.

Вполне может быть, что нужно не искать идеальный вариант компиляции Дракон-схемы в FSM, а делать несколько настраиваемых вариантов.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 16 Июнь, 2018 00:50 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
PSV100 писал(а):
В общем, критерии "выразительности" разнообразны и очень таки.


Ещё немного про выразительность.
Известно, что "бесконечное ожидание" едва ли хорошо. Наверняка нужно как-то обрабатывать ситуацию "систему заклинило".

Так вот. Можно сделать функцию wait(timeLimit: Int, condition: () -> Boolean), которая будет принимать ограничитель по времени (напр, в секундах).

Тогда программа может выглядеть так:
Код:
suspend wait(timeLimit: Int, condition: () -> Boolean) {
  set t;
  while(!t) {
    if (condition()) return;
    yield;
  }
  // В случае "не дождались" можно кинуть исключение, вернуть false и тому подобное.
}

suspend atFloor() {
    while(true) { // если поменять на for(i in 1..3), то будет 3 попытки закрыть дверь
        openDoor();
        set t;
        wait(5) { !closeButton() }
        closeDoor();
        wait(10) {
            if (closedDoor()) {
                // Return прерывает функцию atFloor. Можно написать return@atFloor для наглядности.
                return; // дело сделано, можно принимать решение куда ехать.
            }
            !blockedDoor()
        }
    }
    throw new IllegalStateException("лифт сломался, идите пешком")
}


Взяли и сделали отдельную функцию wait для частоупотребимой операции "дождаться".

С Дракон-схемами такое, очевидно, невозможно, т.к. Дракон не оперирует понятием данных.
С P-схемами такое возможно? Едва ли


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 17 Июнь, 2018 11:10 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
PSV100 писал(а):
А такой -- уже из разряда "а то и более":

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

PSV100 писал(а):
В итоге есть и последствия в виде вынужденного дублирования функционала как "await -> onAwait", "receive -> onReceive" и т.д.

О каком дублировании речь?

PSV100 писал(а):
Причём в случае применения вариаций функции select как whileSelect лямбды, передаваемые "On-функциям", приобретают другую семантику или иной характер (их результат уже управляет циклом).

Удивительно, но факт: код, находящийся внутри цикла while управляет циклом.
Цикл while так работает. whileSelect это лишь функция, которая оборачивает select в while. Чего тут удивительного?

Код:
suspend fun whileSelect(block: SelectorBuilder<Boolean>.() -> Unit): Unit {
    while(select(block)) { /*loop*/ }
}

Даже в простом коде, без всяких suspend, если обвести его в while, то "приобретается другая семантика".


PSV100 писал(а):
И для своих прикладных алгоритмов в случае взаимодействия с функцией аля select напрямую необходимо ещё разобраться с API и принципами построения операций (ожидания, возобновления, с конкретикой концепции "билдеров" для нужных типов, исполняемого контекста и т.д.). Отсюда и возникает потребность в стандартных типах-посредниках как те же "каналы".

И? Т.е. по-вашему, язык должен всячески противодействовать созданию абстракций и запрещать создание "каналов"?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 17 Июнь, 2018 12:12 

Зарегистрирован: Воскресенье, 24 Февраль, 2008 15:32
Сообщения: 3704
Откуда: Москва
Владимир Ситников писал(а):
Дракон не оперирует понятием данных.
Это не так.
1. В гибридных языках (Дракон-С, Дракон-Java и т.д.)
типы данных задаются вторым языком, входящим в состав выбранного гибридного языка

2. В НПЦАП используется оригинальный ДРАКОН имеющий данные, описанные во флокс-таблицах и находящиеся в базе данных. Правда, этот ДРАКОН специализированный, он не описан в открытой литературе, но работает он надежно свыше 20 лет.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 17 Июнь, 2018 14:22 

Зарегистрирован: Среда, 03 Май, 2017 09:55
Сообщения: 151
Владимир Паронджанов писал(а):
Владимир Ситников писал(а):
Дракон не оперирует понятием данных.
Это не так.

Дракон схемы никак не указывают на область видимости переменных.
Вариант 'вызвать схему с параметрами' тоже не предусмотрен.
Рекурсивный вызов -- отдельная песня без хорошего решения.

Или с другой стороны: можно сделать Дракон-схему для управления насосом. Но невозможно указать, что по этой схеме теперь будут работать 5 насосов (у каждого из них может быть своё текущее состояние и своя активная икона на схеме). Иными словами, на уровне Дракон схем нет понятия 'запущенный экземпляр' схемы.

'запуск/останов параллельного процесса'. Это каждый раз один и тот же экземпляр процесса запускается? Или каждый раз новый процесс?
Можно ли запустить 3 процесса, чтобы они работали согласно схеме 'работа насоса', а потом остановить 3ий?

И так далее.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 17 Июнь, 2018 17:00 
Аватара пользователя

Зарегистрирован: Вторник, 04 Октябрь, 2011 17:45
Сообщения: 465
Владимир Ситников писал(а):
Дракон схемы никак не указывают на область видимости переменных.

В ДРАКОН-схемах нет вложенных блоков операторов if, while и т.п. Все выражения находятся на одном уровне.
Раз нет блоков, то нет и переменных, у которых область видимости ограничена блоком.
Область видимости переменных в гибридных ДРАКОН-языках — вся ДРАКОН-схема.
Код:
// Этого в ДРАКОНе нет
if (x == 2) {
    int m = 10; // Область видимости — блок if (x == 2)
    ...
    if (y == 3) {
        int n = 30;  // Область видимости — блок if (y == 3)
        ...
    }
}


Владимир Ситников писал(а):
Вариант 'вызвать схему с параметрами' тоже не предусмотрен.

В гибридных ДРАКОН-языках это делается так:
Вложение:
call_with_params.png
call_with_params.png [ 5.02 КБ | Просмотров: 106 ]


Владимир Ситников писал(а):
Рекурсивный вызов -- отдельная песня без хорошего решения.

Это правда. Такие задачи должна решать среда разработки.

Владимир Ситников писал(а):
Но невозможно указать, что по этой схеме теперь будут работать 5 насосов (у каждого из них может быть своё текущее состояние и своя активная икона на схеме). Иными словами, на уровне Дракон схем нет понятия 'запущенный экземпляр' схемы.

Всё правильно. ДРАКОН изображает алгоритм, а не данные.
Можно составить алгоритм, который запускает 5 насосов.

Владимир Ситников писал(а):
'запуск/останов параллельного процесса'. Это каждый раз один и тот же экземпляр процесса запускается? Или каждый раз новый процесс?

Каждый раз новый процесс.

Владимир Ситников писал(а):
Можно ли запустить 3 процесса, чтобы они работали согласно схеме 'работа насоса', а потом остановить 3ий?

Вложение:
nasosy.png
nasosy.png [ 25.67 КБ | Просмотров: 106 ]


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 17 Июнь, 2018 17:17 

Зарегистрирован: Среда, 07 Январь, 2015 14:53
Сообщения: 733
Владимир Ситников, надо стать пользователем одной из сред и нарабатывать личную практику и области применения.
Естественно, если это Вам нужно.

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 17 Июнь, 2018 21:08 
Аватара пользователя

Зарегистрирован: Вторник, 04 Октябрь, 2011 17:45
Сообщения: 465
Икона Формальные параметры применяется в гибридных ДРАКОН-языках для описания сигнатуры методов.
Это можно назвать привязкой ДРАКОН-схемы к данным.
Вложение:
params.png
params.png [ 20.56 КБ | Просмотров: 86 ]


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 17 Июнь, 2018 21:29 

Зарегистрирован: Воскресенье, 24 Февраль, 2008 15:32
Сообщения: 3704
Откуда: Москва
Степан Митькин писал(а):
Икона Формальные параметры применяется в гибридных ДРАКОН-языках для описания сигнатуры методов.
Это можно назвать привязкой ДРАКОН-схемы к данным.
Вложение:
params.png

Вот полная схема в Wikimedia
https://upload.wikimedia.org/wikipedia/ ... AKON-C.png


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 86 ]  На страницу Пред.  1, 2, 3, 4, 5  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2008-2018, участники конференции «DRAKON.SU», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB