Поведение в реакционно-банановой
Простите меня, я только начинаю изучать реактивно-банановые и FRP.
Автор реактивного банана сделал этот пример по моему предложению, в котором он создает счетчик, который можно увеличить и уменьшить. Он использует функцию accE, которая накапливает события. Я думаю, что мне удалось несколько разобрать тип события, и я смог проверить с ним несколько вещей, но потом я вспомнил, что есть также Поведение. Я просмотрел его, но похоже, что поведение должно использоваться в подобных ситуациях; для изменения существующей переменной, подобно тому, как это происходит с событиями.
Что означает поведение, и каковы его варианты использования?
Ответы
Ответ 1
Семантически, вы
Behavior a = Time -> a
То есть, Behavior a
- это значение типа a
, которое изменяется со временем. В общем, вы ничего не знаете о том, когда изменится Behavior a
, поэтому он окажется довольно плохим выбором для обновления текстового поля одним нажатием кнопки. Тем не менее, было бы легко получить поведение, которое выражает текущее значение числа в примере счетчика. Просто используйте stepper
в потоке событий или, альтернативно, создайте его с нуля таким же образом, за исключением использования accumB
вместо accumE
.
Как правило, все, что вы подключаете к вводу и выводу, всегда будет Event
s, поэтому Behavior
используется для промежуточных результатов.
Предположим, что в данном примере вы хотите добавить новую кнопку, которая запоминает текущее значение, например функцию памяти на простых калькуляторах. Вы начнете с добавления кнопки памяти и текстового поля для запоминаемого значения:
bmem <- button f [text := "Remember"]
memory <- staticText f []
Вы должны иметь возможность запрашивать текущее значение в любое время, поэтому в вашей сети вы добавили бы поведение для его представления.
let currentVal = stepper 0 counter
Затем вы можете подключать события и использовать apply
для чтения значения поведения при каждом нажатии кнопки "Запомнить" и создания события с этой последовательностью значений.
emem <- event0 bmem command
let memoryE = apply (const <$> currentVal) emem
И, наконец, подключите это новое событие к выходному
sink memory [text :== ("", show <$> memoryE)]
Если вы хотите использовать внутреннюю память, то вам снова понадобится Behavior
для его текущего значения... но поскольку мы используем его только для подключения к выходу, нам нужно только событие на данный момент.
Помогает ли это?
Ответ 2
Я согласен с Ankur, а не с Крисом: текстовое поле является значением с течением времени и поэтому естественно хочет быть поведением, а не событием. Причины, которые Крис дает для менее естественного выбора события, - это проблемы реализации и, следовательно, (если они точны) неудачный артефакт реализации реактивного банана. Я бы предпочел, чтобы реализация была улучшена, чем парадигма, используемая неестественно.
Помимо семантической подгонки, прагматически очень полезно выбрать Behavior
над Event
. Вы можете, например, использовать операции Applicative
(например, liftA2
), чтобы комбинировать изменяющееся во времени значение текстового поля с другими изменяющимися во времени значениями (поведением).
Ответ 3
В целом, поведение - это значение, которое изменяется в течение определенного периода времени. Это непрерывное значение, когда события являются дискретными значениями. В случае Поведения всегда присутствует значение.
Например: текст в текстовом поле - это поведение, так как текст может меняться в течение определенного периода времени, но будет текущее значение, где в качестве штриха клавиатуры в событии, поскольку вы не можете запросить ход клавиатуры для своего "текущего", значение.
Ответ 4
Говорящий автор библиотеки.: -)
Видимо, Крис Смит может читать мысли, потому что он точно описывает то, что я думаю.: -)
Но Конус и Артур тоже имеют смысл. Понятно, что счетчик - это значение, которое меняется во времени, а не последовательность событий. Таким образом, думать об этом как Behavior
было бы более подходящим.
К сожалению, поведение не содержит никакой информации о том, когда они будут меняться, "опрос". Теперь я могу попытаться реализовать различные умные схемы, которые минимизируют опрос и, таким образом, позволят эффективные обновления элементов GUI. (Конал делает что-то подобное в оригинальной бумаге.) Но я принял философию "без магии": пользователь библиотеки будет нести ответственность за управление обновления через сами события.
Решением, которое я в настоящее время представляю, является предоставление третьего типа, кроме Event
и Behavior
, а именно Reactive
(имя может быть изменено), которое воплощает в себе качества обоих: концептуально это значение, которое изменяется во времени, но он также поставляется с событием, которое уведомляет об изменениях. Одна из возможных реализаций -
type Reactive a = (a,Event a)
changes :: Reactive a -> Event a
changes (_, e) = e
value :: Reactive a -> Behavior a
value (x, e) = stepper x e
Неудивительно, что это именно тот тип, который ожидает sink
. Это будет включено в будущую версию библиотеки реактивного банана.
EDIT: я выпустил реактивно-банановый версия 0.4, который включает новый тип, который теперь называется Discrete
.