(Non conosco Erlang, e non posso scrivere Haskell, ma penso di poter rispondere comunque)
Bene, in quell'intervista viene fornito l'esempio di una libreria di generazione di numeri casuali. Ecco una possibile interfaccia di stato:
# 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)
L'output potrebbe essere 5 2 7
. A qualcuno a cui piace l'immutabilità, questo è assolutamente sbagliato! Dovrebbe essere 5 5 5
, perché abbiamo chiamato il metodo sullo stesso oggetto.
Quindi cosa sarebbe un'interfaccia stateless? Possiamo visualizzare la sequenza di numeri casuali come un elenco valutato pigramente, in cui next
recupera effettivamente la testa:
let rng = RNG(seed)
let n : rng = rng in
print n
let n : rng = rng in
print n
let n : rng in
print n
Con una tale interfaccia, possiamo sempre tornare a uno stato precedente. Se due parti del tuo codice si riferiscono allo stesso RNG, avranno effettivamente la stessa sequenza di numeri. In una mentalità funzionale, questo è altamente auspicabile.
L'implementazione di questo in un linguaggio di stato non è così complicata. Ad esempio:
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))
Una volta aggiunto un po 'di zucchero sintattico in modo che sembri un elenco, in realtà è piuttosto carino.