我一直在尝试创建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,感觉我可能正朝着正确的方向前进但却迷失在某个地方。
编辑:如果没有人有明确的明确解决方案,那么想法/想法就会很棒!
答案 0 :(得分:5)
两件事:
在Conal Elliott最初的愿景中,行为及时连续,因此他们没有附带功能changes
来指示他们何时发生变化。
返回当前时钟时间的行为将是连续行为的主要示例。它不支持changes
函数,除非您指定一个时间步长(“它每纳秒生成一次'更改'事件”)。但“持续”的观点是缺乏时间步骤。
在我看来,这意味着Conal的行为根本不支持增量更新。在我的reactive-banana库中,我引入了一种新的数据类型Discrete
,它是行为和事件之间的某种混合体。有关基本原理的详细信息,请参阅模块Reactive.Banana.Incremental的文档。
您可能会因为包含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中的某些函数是在第一个参数之前编写的。