FRP应该如何在顶级工作?

时间:2011-10-14 17:02:16

标签: user-interface scala programming-languages functional-programming frp

我一直在尝试创建Functional Reactive Programming framework for 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))
}

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

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

1 个答案:

答案 0 :(得分:5)

两件事:

  1. 在Conal Elliott最初的愿景中,行为及时连续,因此他们没有附带功能changes来指示他们何时发生变化。

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

    在我看来,这意味着Conal的行为根本不支持增量更新。在我的reactive-banana库中,我引入了一种新的数据类型Discrete,它是行为和事件之间的某种混合体。有关基本原理的详细信息,请参阅模块Reactive.Banana.Incremental的文档。

  2. 您可能会因为包含setBackground之类的每个GUI函数而使其与行为而不是普通值一起使用而烦恼。这是高阶函数真正闪耀:包装器总是相同的,你可以表达为更高阶函数;这里有一个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中可能不那么令人愉快,因为Scala中的某些函数是在第一个参数之前编写的。