Я работаю над программой, использующей reactive-banana, и мне интересно, как структурировать мои типы с базовыми строительными блоками FRP.
Например, здесь приведен упрощенный пример из моей реальной программы: например, моя система состоит в основном из виджетов - в моей программе фрагменты текста, которые меняются со временем.
Я мог бы
newtype Widget = Widget { widgetText :: Behavior String }
но я мог бы также иметь
newtype Widget = Widget { widgetText :: String }
и используйте Behavior Widget
, когда я хочу поговорить о изменяющемся во времени поведении. Это, по-видимому, делает вещи "более простыми" и означает, что я могу использовать операции Behavior
более непосредственно, вместо того, чтобы распаковывать и переупаковывать Widgets для этого.
С другой стороны, первый, похоже, избегает дублирования кода, который фактически определяет виджеты, поскольку почти все виджеты меняются со временем, и я обнаруживаю, что я определяю даже те немногие, что не с Behavior
, поскольку это позволяет мне объединить их с другими более последовательно.
В качестве другого примера, с обоими представлениями, имеет смысл иметь экземпляр Monoid
(и я хочу иметь его в своей программе), но реализация для последнего кажется более естественной (поскольку это просто тривиальный подъем список моноидов в newtype).
(Моя фактическая программа использует Discrete
, а не Behavior
, но я не думаю, что это важно.)
Аналогично, следует ли использовать Behavior (Coord,Coord)
или (Behavior Coord, Behavior Coord)
для представления двумерной точки? В этом случае первое кажется очевидным выбором; но когда это пятиэлементная запись, представляющая что-то вроде сущности в игре, выбор кажется менее ясным.
В сущности, все эти проблемы сводятся к:
При использовании FRP на каком уровне следует применять тип Behavior
?
(Тот же вопрос относится и к Event
, хотя и в меньшей степени.)