(我不认识Erlang,也不会写Haskell,但是我仍然可以回答)
好吧,在那次采访中,给出了一个随机数生成库的示例。这是一个可能的有状态接口:
# 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
有了这样的界面,我们总是可以恢复到以前的状态。如果您的代码的两个引用相同的RNG,则它们实际上将获得相同的数字序列。在功能上,这是非常理想的。
以有状态的语言实现此操作并不复杂。例如:
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))
一旦添加了一些语法糖,使其看起来像一个列表,这实际上是非常不错的。