我知道实现此目标的一种方法是在每次更改到达时重新计算状态,但这似乎不切实际。
如果事件发生时应用的更改不是以一种或另一种方式进行分布的,则每次事件发生时您都必须重新计算状态,因为最终状态除了初始状态外,还包括后续更改。即使更改是分布式的,您通常也希望将状态连续转换为下一个状态,因为您希望在达到给定状态时尽快停止进程,并且由于必须计算下一个状态来确定新的是通缉状态。
在函数式编程中,状态更改通常由函数调用和/或函数参数表示。
由于您无法预测何时将计算最终状态,因此不应使用非尾递归函数。一个状态流(每个状态都基于前一个状态)可能是一个很好的选择。
因此,在您的情况下,我将通过以下代码在Scala中回答问题:
import scala.util.Random
val initState = 0.0
def nextState(state: Double, event: Boolean): Double = if(event) state + 0.3 else state - 0.1 // give a new state
def predicate(state: Double) = state >= 1
// random booleans as events
// nb: must be a function in order to force Random.nextBoolean to be called for each element of the stream
def events(): Stream[Boolean] = Random.nextBoolean #:: events()
val states: Stream[Double] = initState #:: states.zip(events).map({ case (s,e) => nextState(s,e)}) // a stream of all the successive states
// stop when the state is >= 1 ;
// display all the states computed before it stopped
states takeWhile(! predicate(_)) foreach println
例如,这可以给出(我简化了输出):
0.0
0.3
0.2
0.5
0.8
val states: Stream[Double] = ...
是计算连续状态的线。
该流的第一个元素是系统的初始状态。zip
将状态流与事件流合并为单个元素对流,每个元素对都是(状态,事件)。map
将每对转换为作为新状态的单个值,并根据旧状态和相关事件进行计算。因此,新状态是先前计算的状态,加上“修改”状态的关联事件。
因此,基本上,您定义了一个潜在的无限状态流,每个新状态都是最后计算的状态和一个新事件的函数。由于流在Scala中(以及其他)是惰性的,因此仅按需计算,因此您不必计算无用的状态,并且可以根据需要计算任意多个状态。
如果您只对遵守谓词的第一个状态感兴趣,则将代码的最后一行替换为:
states find predicate get
哪个检索:
res7: Double = 1.1