Я знаю, що один із способів здійснити це - перерахувати стан кожного разу, коли настає зміна, однак це видається недоцільним.
Якщо зміни, застосовані під час події, не є розподільними, в тій чи іншій мірі вам доведеться перераховувати стан кожного разу, коли трапляється подія, оскільки кінцевий стан є не що інше, як початковий стан плюс послідовні зміни. І навіть якщо зміни є розповсюджуючими, ти, як правило, хочеш послідовно перетворити стан у наступний, оскільки ти хочеш зупинити процес так само швидко, як досягнуто заданий стан, і оскільки ти повинен обчислити наступний стан, щоб визначити, чи новий - розшукова держава.
У функціональному програмуванні зміни стану зазвичай представлені викликами функцій та / або параметрами функції.
Оскільки ви не можете передбачити, коли буде обчислено кінцевий стан, не слід використовувати не хвостову рекурсивну функцію. Потік станів, в якому кожна держава базується на попередньому, може бути хорошою альтернативою.
Тож у вашому випадку я відповів би на наступний код у 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