Wiem, że jednym ze sposobów realizacji tego jest ponowne obliczenie stanu za każdym razem, gdy pojawia się zmiana, jednak wydaje się to niepraktyczne.
Jeśli zmiany zastosowane w momencie wystąpienia zdarzenia nie są rozdzielne, w taki czy inny sposób, będziesz musiał ponownie obliczyć stan za każdym razem, gdy wystąpi zdarzenie, ponieważ stanem końcowym jest tylko stan początkowy plus kolejne zmiany. I nawet jeśli zmiany są rozdzielne, zazwyczaj chcesz sukcesywnie przekształcać stan w następny, ponieważ chcesz zatrzymać proces tak szybko, jak dany stan zostanie osiągnięty, i ponieważ musisz obliczyć następny stan, aby ustalić, czy nowy to stan poszukiwany.
W programowaniu funkcjonalnym zmiany stanu są zwykle reprezentowane przez wywołania funkcji i / lub parametry funkcji.
Ponieważ nie można przewidzieć, kiedy zostanie obliczony stan końcowy, nie należy używać funkcji rekurencyjnej innej niż końcowa. Strumień stanów, w którym każdy stan opiera się na poprzednim, może być dobrą alternatywą.
W twoim przypadku odpowiedziałbym na pytanie następującym kodem w języku 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
Co może na przykład dać (uprościłem wynik):
0.0
0.3
0.2
0.5
0.8
val states: Stream[Double] = ...
to linia, w której obliczane są kolejne stany.
Pierwszym elementem tego strumienia jest stan początkowy systemu. zip
scala strumień stanów ze strumieniem zdarzeń w pojedynczy strumień par elementów, z których każda jest parą (stan, zdarzenie). map
przekształca każdą parę w pojedynczą wartość będącą nowym stanem, obliczoną jako funkcja starego stanu i powiązanego zdarzenia. Nowy stan jest zatem stanem uprzednio obliczonym oraz powiązanym zdarzeniem, które „modyfikuje” stan.
Zasadniczo definiujesz potencjalnie nieskończony strumień stanów, przy czym każdy nowy stan jest funkcją ostatniego obliczonego stanu i nowego zdarzenia. Ponieważ strumienie są leniwe w Scali (między innymi), są obliczane tylko na żądanie, więc nie musisz obliczać bezużytecznych stanów i możesz obliczyć tyle stanów, ile chcesz.
Jeśli interesuje Cię tylko pierwszy stan, który uwzględnia predykat, zamień ostatni wiersz kodu na:
states find predicate get
Który pobiera:
res7: Double = 1.1