纯函数式随机数生成器 - State monad
Pure functional Random number generator - State monad
《Functional Programming in Scala'一书演示了一个纯函数随机数生成器的示例,如下所示
trait RNG {
def nextInt: (Int, RNG)
}
object RNG {
def simple(seed: Long): RNG = new RNG {
def nextInt = {
val seed2 = (seed*0x5DEECE66DL + 0xBL) &
((1L << 48) - 1)
((seed2 >>> 16).asInstanceOf[Int],
simple(seed2))
}
}
}
用法将类似于
val (randomNumber,nextState) = rng.nextInt
我确实得到了它是一个纯函数的部分,因为它 returns 下一个状态 并将它留在 API 客户端上以使用它来下次调用 nextInt
它需要一个随机数,但我不明白的是'第一个随机数将如何生成 因为我们必须提供 seed
至少一次。
是否应该有另一个函数来提升seed
以获得RNG
?如果是这样,那么我们如何期望这个 API 的客户端知道它(因为在非功能性实现中,用户只需调用 nextInt
并且状态由 API 维护)
有人可以给出 Scala 中纯函数随机数生成器的完整示例,并可能将其与一般状态 Monad 联系起来。
Can someone give a full example of pure functional random number generator in Scala and perhaps relate it to state Monad in general.
这个是一个纯功能性的RNG。
val state0 = RNG.simple(1234)
val (r1, state1) = state0.nextInt
val (r2, state2) = state1.nextInt
// etc.
val (x, _) = state1.nextInt
assert (x == r2)
此外,您的示例很好地结合了 Scala 流:
def randStream(r: RNG): Stream[Int] = r.nextInt match {
case (value, next) => value #:: randStream(next)
}
val rng = randStream(RNG.simple(123))
println(rng.take(10).toList)
println(rng.take(5).toList)
那个随机生成器 RNG
是纯函数的,对于相同的输入,你总是得到相同的输出。非纯功能部分留给那个API(你)的用户。
要以纯功能方式使用 RNG
,您必须始终使用相同的初始值对其进行初始化,但随后您将始终获得相同的数字序列,这不是很有用。
否则,您将不得不依赖 RNG
对外部系统的初始化(通常是挂钟时间),从而引入副作用(拜拜纯函数)。
val state0 = RNG.simple(System.currentTimeMillis)
val (rnd1, state1) = state0.nextInt
val (rnd2, state2) = state1.nextInt
val (rnd3, state3) = state2.nextInt
println(rnd1, rnd2, rnd3)
[编辑]
受@Aivean 回答的启发,我创建了我的随机版本 Stream
:
def randoms: Stream[Int] = Stream.from(0)
.scanLeft((0, RNG.simple(System.currentTimeMillis)))((st, _) => st._2.nextInt)
.tail
.map(_._1)
println(randoms.take(5).toList)
println(randoms.filter(_ > 0).take(3).toList)
一个递归函数,派生自@Aivean Stream
基于函数,
def rand(n: Int, r: RNG): List[Int] = {
if (n < 0) List()
else {
val (value, next) = r.nextInt
value :: rand(n-1, next)
}
}
要获得5
个随机值,
rand(5, RNG.simple(System.currentTimeMillis) )
《Functional Programming in Scala'一书演示了一个纯函数随机数生成器的示例,如下所示
trait RNG {
def nextInt: (Int, RNG)
}
object RNG {
def simple(seed: Long): RNG = new RNG {
def nextInt = {
val seed2 = (seed*0x5DEECE66DL + 0xBL) &
((1L << 48) - 1)
((seed2 >>> 16).asInstanceOf[Int],
simple(seed2))
}
}
}
用法将类似于
val (randomNumber,nextState) = rng.nextInt
我确实得到了它是一个纯函数的部分,因为它 returns 下一个状态 并将它留在 API 客户端上以使用它来下次调用 nextInt
它需要一个随机数,但我不明白的是'第一个随机数将如何生成 因为我们必须提供 seed
至少一次。
是否应该有另一个函数来提升seed
以获得RNG
?如果是这样,那么我们如何期望这个 API 的客户端知道它(因为在非功能性实现中,用户只需调用 nextInt
并且状态由 API 维护)
有人可以给出 Scala 中纯函数随机数生成器的完整示例,并可能将其与一般状态 Monad 联系起来。
Can someone give a full example of pure functional random number generator in Scala and perhaps relate it to state Monad in general.
这个是一个纯功能性的RNG。
val state0 = RNG.simple(1234)
val (r1, state1) = state0.nextInt
val (r2, state2) = state1.nextInt
// etc.
val (x, _) = state1.nextInt
assert (x == r2)
此外,您的示例很好地结合了 Scala 流:
def randStream(r: RNG): Stream[Int] = r.nextInt match {
case (value, next) => value #:: randStream(next)
}
val rng = randStream(RNG.simple(123))
println(rng.take(10).toList)
println(rng.take(5).toList)
那个随机生成器 RNG
是纯函数的,对于相同的输入,你总是得到相同的输出。非纯功能部分留给那个API(你)的用户。
要以纯功能方式使用 RNG
,您必须始终使用相同的初始值对其进行初始化,但随后您将始终获得相同的数字序列,这不是很有用。
否则,您将不得不依赖 RNG
对外部系统的初始化(通常是挂钟时间),从而引入副作用(拜拜纯函数)。
val state0 = RNG.simple(System.currentTimeMillis)
val (rnd1, state1) = state0.nextInt
val (rnd2, state2) = state1.nextInt
val (rnd3, state3) = state2.nextInt
println(rnd1, rnd2, rnd3)
[编辑]
受@Aivean 回答的启发,我创建了我的随机版本 Stream
:
def randoms: Stream[Int] = Stream.from(0)
.scanLeft((0, RNG.simple(System.currentTimeMillis)))((st, _) => st._2.nextInt)
.tail
.map(_._1)
println(randoms.take(5).toList)
println(randoms.filter(_ > 0).take(3).toList)
一个递归函数,派生自@Aivean Stream
基于函数,
def rand(n: Int, r: RNG): List[Int] = {
if (n < 0) List()
else {
val (value, next) = r.nextInt
value :: rand(n-1, next)
}
}
要获得5
个随机值,
rand(5, RNG.simple(System.currentTimeMillis) )