FRP在顶层应该如何工作?

Posted

技术标签:

【中文标题】FRP在顶层应该如何工作?【英文标题】:How should FRP work at the top level? 【发布时间】:2011-12-07 22:25:32 【问题描述】:

我一直在尝试创建Functional Reactive Programming framework for 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,感觉我可能会朝着正确的方向前进,但在某个地方迷路了。

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

【问题讨论】:

我愿意为要求将论文翻译成 Scala 的问题添加一些赏金。 @ziggystar 我同意这将是惊人的。研究 FRP 的主要问题之一是必须爬过不熟悉的 Haskell 语法。不过,在 Stack Overflow 上要求这样做是否正确? 也许唯一的反对点是问题应该有合理的范围。因此,答案不应该太长。但我认为这个问题本身对 SO 来说是可以的。但是在合理的水平上翻译这篇论文需要一些时间。我更怀疑它会发布在博客上。 您可能会在这里得到答案:***.com/questions/5095728/… @Szabolcs 问题在于 Scala.react 并不是真正的 FRP。不过还是谢谢你的链接。 【参考方案1】:

两件事:

    在 Conal Elliott 的最初设想中,行为在时间上是连续的,因此它们不带有指示它们何时发生变化的函数 changes

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

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

    您可能对包装每个 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 中可能不那么令人愉快,其中一些函数是在第一个参数之前编写的。

【讨论】:

我有一个类似 set 的函数,是的,它在 Scala 中并没有那么好(主要是因为 background 属性和其他属性通常不能从课堂外获得)。然而,它看起来是最好的方法。另外,只是为了确认我的实现中的行为实际上是连续的。 changes 函数返回一个 EventSource,它监听 Behavior 的变化(它更像是一个实用程序)。出于兴趣,这里的reactimate 函数是什么(changes 指的是我的changes)? @Oetzi:嗯,返回当前时钟时间的行为将是连续行为的主要示例。你不能真正为它写一个changes 函数,因为它“一直”在变化。 @Oetzi:reactimate 函数是您的 .each 函数的一部分;后者分解为fmapreactimate 部分。 changes 函数应该是相同的。 我了解changes 函数在技术上并不准确。但是,您将如何代表这里的颜色行为是我要问的。你会使用 Discrete 而不是 Behaviour 吗? @Oetzi:是的,我会使用Discrete 类型。再说一次,也可以选择尝试以在内部使用changes 函数以提高效率但不导出它的方式来实现行为;这将避免 Discrete 类型不幸地重复功能。或者您可以默认使Behavior 离散,但这会使语义稍微复杂化(不再连续Behavior a = Time -> a)。我会说,这取决于你和你的口味。

以上是关于FRP在顶层应该如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

金山财富沙龙 | 企业融资:顶层架构设计与资本的规则

如何在 Javascript 中实现 Haskell 的 FRP Behavior 类型?

「技术人生」:技术同学应该如何理解业务?

FRP(反应式):如何使用 filterS?

「技术人生」第6篇:技术同学应该如何理解业务?

如何在最顶层的 NSPanel 中获取键盘事件?