Как обрабатывать два сигнала в зависимости друг от друга?

Я прочитал Устаревание шаблона Observer с помощью Scala.React и нашел реактивное программирование очень интересным.

Но есть момент, который я не могу понять: автор описал сигналы как узлы в DAG (направленный ациклический граф). А что, если у вас есть два сигнала (или источника событий, или модели, w/e), зависящие друг от друга? то есть «двусторонняя привязка», как модель и представление в программировании веб-интерфейса.

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


person Lai Yu-Hsuan    schedule 27.01.2014    source источник
comment
Ваш вопрос относится к scala.react? Последнее, что я помню, это было не так удобно   -  person nafg    schedule 30.01.2014
comment
@dcsbral / OP, не могли бы вы уточнить?   -  person nafg    schedule 31.01.2014
comment
@nafg Вы неправильно написали мой никнейм, поэтому я не увидел ваш комментарий. Я ожидаю, что вопрос действительно будет касаться scala.react. Хотя мне бы хотелось, чтобы вы внесли свой вклад в то, как с этим справляется ваша собственная структура.   -  person Daniel C. Sobral    schedule 05.02.2014
comment
Должен сказать, я очень разочарован ответами. Все они, кажется, рассказывают о том, как другие люди решили эту проблему в другом программном обеспечении FRP, или советуют вам прочитать чью-то статью, в которой говорится о предмете, и извлечь из нее свои собственные ответы. Ответы Stack Overflow не должны быть такими. Я присудил награду за единственный ответ, который на самом деле говорит о решении, хотя он (ответ) является своего рода отговоркой.   -  person Daniel C. Sobral    schedule 05.02.2014
comment
@DanielC.Sobral - извините за это. В реактивном (по крайней мере, в настоящее время) это не сложно, поскольку он не основан на явном графе. Вы можете просто обновить, например. Var, от которого зависит сигнал. Также есть .distinct и .nonrecursive для предотвращения бесконечных циклов. В будущем, хотя по воле Б-га, я надеюсь, что у меня будет способ использовать его на основе графа.   -  person nafg    schedule 07.02.2014
comment
Вопрос не напрямую про Scala.React, приветствуется любое решение по поводу реактивного программирования. Кстати, я нашел запись в блоге , объясняющую как Bacon.js решает эту проблему.   -  person Lai Yu-Hsuan    schedule 10.02.2014


Ответы (4)


Зависимости циклов в реактивном языке программирования можно обрабатывать с помощью различных семантик. Тот, который, по-видимому, был выбран в scala.React, относится к синхронным реактивным языкам и, в частности, к языку Esterel. Вы можете получить хорошее объяснение этой семантики и ее альтернатив в статье «Синхронные языки 12 лет спустя» Benveniste, A.; Каспи, П.; Эдвардс, SA; Хальбвакс, Н.; Ле Герник, П. ; де Симоне, Р. и доступно по адресу http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=1173191&tag=1 или http://virtualhost.cs.columbia.edu/~sedwards/papers/benveniste2003synchronous.pdf.

person Pierre Boulet    schedule 30.01.2014

Отвечаю здесь @Matt Carkci, так как одного комментария недостаточно

В бумажном разделе 7.1 Распространение изменений у вас есть

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

и далее в разделе 7.6 Несоответствие уровней

Поэтому нам нужно подготовиться к тому, что непрозрачный узел n получит доступ к другому узлу, находящемуся на более высоком топологическом уровне. Каждый узел, который считывается во время оценки n, сначала проверяет, превышает ли текущий уровень распространения, поддерживаемый распространителем, уровень узла. Если это так, он действует как обычно, в противном случае выдается исключение несоответствия уровня, содержащее ссылку на себя, которое перехватывается только в основном цикле распространения. Затем распространитель поднимает n, сначала изменяя его уровень на уровень выше узла, вызвавшего исключение, повторно вставляя n в очередь распространения (поскольку его уровень изменился) для последующего использования. вычисление в тот же ход, а затем транзитивно поднимает все иждивенцы n.

Хотя нет упоминания о каком-либо топологическом ограничении (циклическое или ациклическое), кое-что не ясно. (по крайней мере мне)

Сначала возникает вопрос, как определяется топологический порядок.

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

Что вы думаете?

person pagoda_5b    schedule 29.01.2014
comment
en.wikipedia.org/wiki/Topological_sorting -- Топологическое упорядочение возможно тогда и только тогда, когда граф не имеет направленных циклов, т. е. если это ориентированный ациклический граф (ДАГ). - person Boyd Stephen Smith Jr.; 30.01.2014

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

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


Редактировать после второго сообщения пользователя pagoda_5b

Одно заявление в газете заставило меня обратить внимание...

Для правильно упорядоченных графов этот процесс монотонно переходит на более высокие уровни, что обеспечивает непротиворечивость данных, т. е. отсутствие сбоев.

Для меня это говорит о том, что циклы не разрешены в рамках Scala.React. Казалось бы, цикл между двумя узлами заставляет систему постоянно пытаться поднять уровень обоих узлов навсегда.

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

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

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

Поток данных не обязательно должен быть таким сложным. Это просто совсем другой способ думать о программировании. Я предлагаю вам ознакомиться с книгой Дж. Пола Морисона "Программирование на основе потоков", где вы найдете протестированную версию потока данных. или моя книга (после завершения).

person Matt Carkci    schedule 28.01.2014

Проверьте свои знания MVC. Представление не обновляет модель, поэтому не будет посылать ей сигналы. Контроллер обновляет модель. Для преобразователя C/F у вас будет два контроллера (один для управления F, включенный для управления C). Оба контроллера будут посылать сигналы в одну модель (которая хранит единственную реальную температуру, Кельвин, в формат без потерь). Модель отправляет сигналы в два отдельных вида (один для вида C, один для вида F). Никаких циклов.

Основываясь на ответе @pagoda_5b, я бы сказал, что вам, вероятно, разрешено иметь циклы (7.6 должен справиться с этим за счет производительности), но вы должны гарантировать отсутствие бесконечного регресса. Например, вы можете сделать так, чтобы контроллеры также получали сигналы от модели, если вы гарантируете, что получение указанного сигнала никогда не приведет к отправке сигнала обратно в модель.

Я думаю, что приведенное выше описание является хорошим, но оно использует слово «сигнал» в стиле, отличном от FRP. «Сигналы» в приведенном выше на самом деле сообщения. Если описание в 7.1 правильное и полное, циклы в сигнальном графе всегда будут вызывать бесконечный регресс, поскольку обработка зависимостей узла приведет к обработке узла, и наоборот, ad inf.

Как сказал @Matt Carkci, существуют фреймворки FRP, которые допускают циклы, по крайней мере, в ограниченной степени. Они либо не будут основаны на проталкивании, либо будут интересным образом использовать нестрогость, обеспечивать монотонность или вводить «искусственные» задержки, чтобы при расширении графа сигналов во временном измерении (превращая его в граф значений) циклы исчезали.

person Boyd Stephen Smith Jr.    schedule 29.01.2014