(Я не знаю Эрланга и не могу написать на Хаскеле, но, тем не менее, могу ответить)
Что ж, в этом интервью приведен пример библиотеки генерации случайных чисел. Вот возможный интерфейс с отслеживанием состояния:
# create a new RNG
var rng = RNG(seed)
# every time we call the next(ceil) method, we get a new random number
print rng.next(10)
print rng.next(10)
print rng.next(10)
Выход может быть 5 2 7
. Для того, кто любит неизменность, это совершенно неправильно! Так должно быть5 5 5
, потому что мы вызвали метод для одного и того же объекта.
Так что бы был интерфейс без состояния? Мы можем просмотреть последовательность случайных чисел в виде лениво вычисляемого списка, где next
фактически извлекается голова:
let rng = RNG(seed)
let n : rng = rng in
print n
let n : rng = rng in
print n
let n : rng in
print n
С таким интерфейсом мы всегда можем вернуться к предыдущему состоянию. Если две части вашего кода ссылаются на один и тот же ГСЧ, они фактически получат одинаковую последовательность чисел. В функциональном мышлении это очень желательно.
Реализация этого на государственном языке не так уж сложна. Например:
import scala.util.Random
import scala.collection.immutable.LinearSeq
class StatelessRNG (private val statefulRNG: Random, bound: Int) extends LinearSeq[Int] {
private lazy val next = (statefulRNG.nextInt(bound), new StatelessRNG(statefulRNG, bound))
// the rest is just there to satisfy the LinearSeq trait
override def head = next._1
override def tail = next._2
override def isEmpty = false
override def apply(i: Int): Int = throw new UnsupportedOperationException()
override def length = throw new UnsupportedOperationException()
}
// print out three nums
val rng = new StatelessRNG(new Random(), 10)
rng.take(3) foreach (n => println(n))
Когда вы добавляете немного синтаксического сахара, чтобы он выглядел как список, это на самом деле довольно приятно.