Подтвердить что ты не робот

Правильно ли отображается "Сигнальное" представление функционального реактивного программирования?

Я изучал FRP и нашел множество различных реализаций. Одна модель, которую я видел, является той, которую я буду называть представлением "Сигнал". Это важно сочетает события и поведение в одном объекте.

Во-первых, сигнал - это объект, значение которого является Поведением. Во-вторых, сигнал имеет поток событий, который можно увидеть и использовать как стандартную структуру данных (вы можете использовать "каждый", "карту" и "фильтр" и т.д. Для сигнала, чтобы определить, как реагируют события). Например, я могу это сделать (где "время" является сигнальным представлением времени):

time.each { t => print(t) } // every time there is a 'tick' the current time is printed
a = time * 5 //where 'a' would be a dynamic value always up to date with time

Правильно ли это представление FRP или есть ли какие-либо проблемы? Мне очень нравится, как это работает, а также как просто описать лично, но я не уверен, что это правильно.

4b9b3361

Ответ 1

К сожалению, совместное "событие" и "поведение" в единый "сигнал" не работает так хорошо.

Большинство основанных на сигнатуре FRP-реализаций, которые, как мне известно, создают дополнительный тип, похожий на событие, по строкам

type Event a = Signal (Maybe a)

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

Основной аргумент против сигналов состоит в том, что они не могут представлять непрерывное поведение во времени, поскольку они должны удовлетворять дискретным событиям. В "Конале Эллиоте "Оригинальное видение" , поведение было простым непрерывным временем работы

type Behavior a = Time -> a
-- = function that takes the current time as parameter and returns
--   the corresponding value of type  a

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

type Event a = [(Time,a)]
-- list of pairs of the form (current time, corresponding event value)

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

Аргумент различия между поведением и событиями заключается в том, что их API совсем другой. Главное, что у них разные типы продуктов:

(Behavior a , Behavior b) = Behavior (a,b)
(Event a    , Event b   ) = Event (a :+: b)

В словах: пара поведений совпадает с поведением пар, но пара событий совпадает с событием из любого компонента/канала. Другое дело, что существуют две операции

(<*>) :: Behavior (a -> b) -> Behavior a -> Behavior b
apply :: Behavior (a -> b) -> Event a    -> Event b

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

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

(Полное раскрытие: я реализовал библиотеку FRP под названием reactive-banana в Haskell.)