11

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

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

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

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

这感觉有点乱。有人对这是否是一种不好的方法有任何建议吗?我今天一直在看 Elliott 的Push-Pull FRP,感觉我可能会朝着正确的方向前进,但在某个地方迷路了。

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

4

1 回答 1

6

两件事情:

  1. 在 Conal Elliott 的最初设想中,行为在时间上是连续的,因此它们不具有changes指示它们何时发生变化的功能。

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

    在我看来,这意味着 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
    

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

于 2011-10-15T07:48:28.630 回答