Eu sei que uma maneira de implementar isso é recalcular o estado toda vez que uma mudança chega, no entanto, isso parece impraticável.
Se as alterações aplicadas quando um evento ocorrer não forem distributivas, de uma maneira ou de outra, você terá que recalcular o estado toda vez que um evento ocorrer, pois o estado final nada mais é do que o estado inicial, além de alterações sucessivas. E mesmo que as alterações sejam distributivas, você normalmente deseja transformar sucessivamente um estado no próximo, pois deseja interromper seu processo o mais rápido que um determinado estado é alcançado e desde que seja necessário calcular o próximo estado para determinar se o novo é o estado desejado.
Na programação funcional, as alterações de estado são normalmente representadas por chamadas de função e / ou parâmetros de função.
Como você não pode prever quando o estado final será calculado, você não deve usar a função recursiva não-cauda. Um fluxo de estados, no qual cada estado se baseia no anterior, poderia ser uma boa alternativa.
Portanto, no seu caso, eu responderia à pergunta pelo seguinte código, em 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
O que pode dar, por exemplo (simplifiquei a saída):
0.0
0.3
0.2
0.5
0.8
val states: Stream[Double] = ...
é a linha em que estados sucessivos são calculados.
O primeiro elemento desse fluxo é o estado inicial do sistema. zip
mescla o fluxo de estados com o fluxo de eventos em um único fluxo de pares de elementos, cada par sendo um (estado, evento). map
transforma cada par em um único valor, sendo o novo estado, calculado em função do estado antigo e do evento associado. Um novo estado é, portanto, um estado calculado anteriormente, mais o evento associado que "modifica" o estado.
Então, basicamente, você define um fluxo potencialmente infinito de estados, cada novo estado sendo uma função do último estado calculado e um novo evento. Como os fluxos são preguiçosos no Scala (entre outros), só são computados sob demanda, portanto você não precisa calcular estados inúteis e pode calcular quantos estados desejar.
Se você está interessado apenas no primeiro estado que respeita o predicado, substitua a última linha do código por:
states find predicate get
Que recupera:
res7: Double = 1.1