Как должен работать FRP на верхнем уровне? - PullRequest
11 голосов
/ 14 октября 2011

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

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

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

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

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

РЕДАКТИРОВАТЬ: Если ни у кого нет определенного четкого решения, то идеи / мысли были бы великолепны!

1 Ответ

5 голосов
/ 15 октября 2011

Две вещи:

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

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

    На мой взгляд, это означает, что поведение в смысле Конала вообще не поддерживает добавочные обновления.В моей библиотеке реагирующий банан я ввел новый тип данных Discrete, который является своего рода гибридом между поведением и событиями.См. Документацию модуля Reactive.Banana.Incremental для получения более подробной информации об обосновании.

  2. Вероятно, вас раздражает то, что вы обернули каждую функцию GUI, например 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, где некоторые функции пишутся перед первым аргументом.

...