Я знаю, что один из способов реализовать это - пересчитывать состояние каждый раз, когда приходит изменение, однако это кажется непрактичным.
Если изменения, применяемые при возникновении события, не являются распределительными, так или иначе, вам придется пересчитывать состояние каждый раз, когда происходит событие, так как конечное состояние - это не что иное, как начальное состояние плюс последовательные изменения. И даже если изменения носят дистрибутивный характер, вы, как правило, хотите последовательно преобразовать состояние в следующее, поскольку вы хотите остановить процесс так же быстро, как достигается заданное состояние, и поскольку вам нужно вычислить следующее состояние, чтобы определить, является ли новый разыскиваемый штат.
В функциональном программировании изменения состояния обычно представлены вызовами функций и / или параметрами функций.
Поскольку вы не можете предсказать, когда будет вычислено конечное состояние, вы не должны использовать нехвостовую рекурсивную функцию. Поток состояний, в котором каждое состояние основано на предыдущем, может быть хорошей альтернативой.
Так что в вашем случае я бы ответил на вопрос следующим кодом в 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