我在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'的最后一个'样本'(最后一次出现时的值) )。如果最后一次出现的时间是过去那么我们将最终使用过去的时间来评估“滑块”,该时间打破了上面的规则集(以及您的原始假设)。我可以看到几种解决方法:
我也可以简单地不实现'sample'或删除'stepper'/'switcher'(但我真的不想做这些事情中的任何一个)。有没有人对此有任何想法?我在这里误解了什么吗?
答案 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建议的函数。