在FRP中实现快照

时间:2012-03-08 23:02:53

标签: scala haskell programming-languages semantics frp

我在Scala中实现了一个FRP框架,我似乎遇到了一个问题。受到一些思考的启发,这个问题我决定限制我的框架的公共接口,所以行为只能在'现在'中进行评估,即:

behaviour.at(now) 

这也符合Conal在Fran论文中的假设,即行为只会在不断增加的时间进行评估/抽样。它确实限制了行为的转换,但是我们发现自己遇到了代表一些输入的行为的巨大问题:

val slider = Stepper(0, sliderChangeEvent) 

使用此行为,评估未来值将是不正确的,并且评估过去的值将需要无限量的内存(必须存储“slider”事件中使用的所有事件)。

我在针对此限制的行为上的“快照”操作规范时遇到问题。我的问题最好用一个例子解释(使用上面提到的滑块):

val event = mouseB // an event that occurs when the mouse is pressed 
val sampler = slider.snapshot(event) 
val stepper = Stepper(0, sampler) 

我的问题是,如果执行此代码时发生'mouseB'事件,那么'stepper'的当前值将是'slider'的最后一个'样本'(最后一次出现时的值) )。如果最后一次出现的时间是过去那么我们将最终使用过去的时间来评估“滑块”,该时间打破了上面的规则集(以及您的原始假设)。我可以看到几种解决方法:

  1. 我们'记录'过去(保持事件中所有过去的事件),允许用过去的时间评估行为(使用无限量的记忆)
  2. 我们修改'snapshot'以获取时间参数(“此时间之后的样本”)并强制执行该时间> = now
  3. 在一个更古怪的举动中,我们可以以某种方式将FRP对象的创建限制为程序的初始设置,并且仅在此设置完成后开始处理事件/输入
  4. 我也可以简单地不实现'sample'或删除'stepper'/'switcher'(但我真的不想做这些事情中的任何一个)。有没有人对此有任何想法?我在这里误解了什么吗?

3 个答案:

答案 0 :(得分:3)

据我所知,您担心竞争状况:如果在代码执行时发生事件,会发生什么。

纯功能代码不想知道它被执行了。功能技术在纯设置中处于最佳状态,因此执行代码的顺序无关紧要。摆脱这种困境的一种方法是假装每一个变化发生在一个敏感的(内部的,可能的)命令式代码中;假装FRP框架中的任何功能声明都在0时间内发生,因此在声明期间不可能发生变化。

声明行为和事物的代码段中,没有人应该睡觉,或者真正做任何时间敏感的事情。从本质上讲,与FRP对象一起使用的代码应该是纯粹的,那么你就没有任何问题。

这不一定排除在多个线程上运行它,但为了支持您可能需要重新组织内部表示。欢迎来到FRP库实施的世界 - 我怀疑在此过程中您的内部表示会多次波动。 : - )

答案 1 :(得分:3)

哦,我明白你的意思了。

我认为你的“你只能'现在'采样”的限制是不够紧张的。它需要更强一些,以避免回顾过去。由于您使用的是now的环境概念,我将根据它来定义行为构造函数(只要now不能通过仅仅执行定义来推进,根据我的上一个答案,会变得凌乱)。例如:

  

Stepper(i,e)i区间内值[now,e1]的行为(其中e1是   e之后首次出现now的时间,以及之后最近出现e的值。

使用这种语义,你对stepper的值进入这个难题的预测被解除了,步进器现在将具有值0.我不知道这个语义是否适合你,但对我来说这似乎很自然。

答案 2 :(得分:0)

我对你的困惑感到困惑。我看到的方式是Stepper会在事件发生时将行为“设置”为新值。那么,接下来会发生什么:

  

事件mouseB发生的瞬间,将会读取slider行为的值(snapshot)。此值将“设置”为行为stepper

所以,Stepper确实会“记住”过去的价值观;关键是它只会记住过去的最新值,而不是一切。

从语义上讲,最好将Stepper建模为像luqui建议的函数。