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

Как FRP будет работать на высшем уровне?

Я экспериментировал с созданием функционально-реактивного программного обеспечения для Scala. В настоящий момент меня смущает одна вещь: как текущие реализации имеют дело с представлением поведения на верхнем уровне. Чтобы объяснить, что я имею в виду, я приведу пример. Скажем, у меня есть JPanel, и я хочу это сделать:

 JPanel panel = new Panel()
 panel.setBackground(new Behaviour(time => Color.red))

Несмотря на то, что цвет является статическим, мы хотим, чтобы фон панели обновлялся при изменении значений поведенческих обновлений. То, как я это делал до сих пор, состоит в том, чтобы по существу создать дискретизированное поведение с использованием событий (доступное с помощью функции changes в Behaviors). Это в основном просто источник событий, который возникает всякий раз, когда изменяется поведение. Используя это, реализация setBackground здесь будет:

def setBackground(color : Behaviour[Color]) {
  super.setBackground(color.now)
  color.changes.each(change => super.setBackground(change))
}

Это кажется грязным. Есть ли у кого-нибудь предложения о том, плохо это или нет? Сегодня я смотрел на Elliott Push-Pull FRP, и мне кажется, что я могу идти в правильном направлении, но где-то теряюсь.

EDIT: Если у кого-то нет четкого решения, то идеи/мысли будут замечательными!

4b9b3361

Ответ 1

Две вещи:

  • В оригинальном видении Конала Эллиота поведение постоянно, поэтому они не имеют функции changes, которая указывает, когда они изменяются.

    Поведение, возвращающее текущее время, будет ярким примером непрерывного поведения. Он не поддерживает функцию changes, если вы не указали временной шаг ( "он генерирует событие" change "каждую наносекунду" ). Но точкой "непрерывного" является отсутствие временного шага.

    На мой взгляд, это означает, что поведение в смысле Conal не поддерживает инкрементные обновления вообще. В моей библиотеке reactive-banana я ввел новый тип данных Discrete, который является своего рода гибридом между поведением и событиями. Подробнее об этом можно узнать в документации модуля Reactive.Banana.Incremental.

  • Вы, вероятно, недовольны тем, что обмениваете каждую функцию графического интерфейса, например setBackground, чтобы она работала с поведением вместо простых значений. Это функции высшего порядка, которые действительно светят: обертка всегда одна и та же, вы можете выразить ее как функцию более высокого порядка; здесь версия Haskell:

    set' :: Property a -> Behavior a -> IO ()
    set' property behavior = do
         set property (now behavior)
         each (\a -> set property a) (changes behavior)          
    
    each f event = reactimate (fmap f event) -- helper definition
    
    example = set' background red
    

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