FRP应该如何在顶级工作?

sea*_*owg 11 user-interface programming-languages functional-programming scala frp

我一直在尝试为Scala创建功能反应式编程框架.目前我很困惑的一件事是当前的实现如何处理在顶层表示行为.为了解释我的意思,我将举一个例子.说我有一个JPanel,我想这样做:

 JPanel panel = new Panel()
 panel.setBackground(new Behaviour(time => Color.red))
Run Code Online (Sandbox Code Playgroud)

虽然这里的颜色是静态的,但我们希望在行为更新值时更新面板背景.到目前为止,我完成它的方法是使用事件(通过changes行为上的函数可访问)基本上创建一个离散化的行为.这基本上只是行为发生变化时发生的事件源.使用这个setBackground的实现在这里:

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

这感觉有点乱.有没有人有任何关于这是否是一个坏方法的建议?我今天一直在关注Elliott的Push-Pull FRP,感觉我可能会朝着正确的方向前进但却迷失在某个地方.

编辑:如果没有人有明确的明确解决方案,那么想法/想法会很棒!

Hei*_*mus 5

两件事情:

  1. 在Conal Elliott最初的愿景中,行为在时间上是连续的,因此它们没有带有changes表明它们何时发生变化的功能.

    返回当前时钟时间的行为将是连续行为的主要示例.它不支持changes函数,除非您指定一个时间步长("它每纳秒生成一次'更改'事件").但"持续"的观点是缺乏时间步骤.

    在我看来,这意味着Conal意义上的行为根本不支持增量更新.在我的反应香蕉库中,我引入了一种新的数据类型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
    
    Run Code Online (Sandbox Code Playgroud)

    当然,这在很大程度上依赖于Haskell的语法,并且在Scala中可能不那么令人愉快,因为在Scala中,一些函数是在第一个参数之前编写的.