Je sais qu'une façon de mettre en œuvre cela est de recalculer l'état chaque fois qu'un changement arrive, mais cela semble peu pratique.
Si les modifications appliquées lorsqu'un événement se produit ne sont pas distributives, d'une manière ou d'une autre, vous devrez recalculer l'état chaque fois qu'un événement se produit, car l'état final n'est rien d'autre que l'état initial, plus les modifications successives. Et même si les modifications sont distributives, vous voulez généralement transformer successivement un état en un autre, car vous voulez arrêter votre processus aussi rapidement qu'un état donné est atteint, et puisque vous devez calculer l'état suivant pour déterminer si le nouveau est l'état voulu.
Dans la programmation fonctionnelle, les changements d'état sont généralement représentés par des appels de fonction et / ou des paramètres de fonction.
Comme vous ne pouvez pas prédire quand l'état final sera calculé, vous ne devez pas utiliser la fonction récursive non-queue. Un flux d'états, dans lequel chaque état est basé sur le précédent, pourrait être une bonne alternative.
Donc dans votre cas, je répondrais à la question par le code suivant, en 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
Ce qui peut donner, par exemple (j'ai simplifié la sortie):
0.0
0.3
0.2
0.5
0.8
val states: Stream[Double] = ...
est la ligne où les états successifs sont calculés.
Le premier élément de ce flux est l'état initial du système. zip
fusionne le flux d'états avec le flux d'événements en un seul flux de paires d'éléments, chaque paire étant un (état, événement). map
transforme chaque paire en une seule valeur étant le nouvel état, calculé en fonction de l'ancien état et de l'événement associé. Un nouvel état est donc un état précédemment calculé, plus l'événement associé qui "modifie" l'état.
Donc, fondamentalement, vous définissez un flux potentiellement infini d'états, chaque nouvel état étant fonction du dernier état calculé et d'un nouvel événement. Étant donné que les flux sont paresseux dans Scala (entre autres), ils ne sont calculés qu'à la demande, vous n'avez donc pas à calculer des états inutiles et vous pouvez calculer autant d'états que vous le souhaitez.
Si vous n'êtes intéressé que par le premier état qui respecte le prédicat, remplacez la dernière ligne de code par:
states find predicate get
Qui récupère:
res7: Double = 1.1