【问题标题】:Pure functional Random number generator - State monad纯函数随机数生成器 - 状态单子
【发布时间】:2015-08-04 20:33:05
【问题描述】:

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

我确实知道它是一个纯函数,因为它返回 下一个状态 并将其留在 API 客户端上,以便在下次需要随机数时使用它来调用 nextInt但我不明白的是'如何生成第一个随机数,因为我们必须至少提供一次seed

是否应该有另一个函数来提升seed 以获得RNG?如果是这样,那么我们如何期望这个 API 的客户端知道它(因为在非功能实现中,用户只需调用 nextInt 并且状态由 API 维护)

谁能给出一个 Scala 中纯函数式随机数生成器的完整示例,并可能将其与一般的状态 Monad 联系起来。

【问题讨论】:

  • 顺便说一句,如果你真的想学习纯函数式编程,你应该试试 Haskell。因为在 Haskell 中,如果不使用 IO monad 或在更改状态时使用 State monad,就无法引入副作用。即使您不每天使用它,对我来说它也是学习函数式编程的最佳语言。相反,Scala 过于宽松,在实际项目中使用可能会很好,但很难看出函数式世界和命令式世界之间的界限。
  • 关于完全没有副作用,Haskell 背后的伟大思想家之一西蒙·佩顿·琼斯(Simon Peyton Jones)在这里说得很好:youtube.com/watch?v=iSmkqocn0oQ#t=3m17

标签: scala functional-programming monads state-monad


【解决方案1】:

随机生成器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)

【讨论】:

    【解决方案2】:

    此外,您的示例很好地结合了 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)
    

    【讨论】:

      【解决方案3】:

      谁能给出一个 Scala 中纯函数式随机数生成器的完整示例,并可能将其与一般的状态 Monad 联系起来。

      这个一个纯粹的函数式RNG。

      val state0 = RNG.simple(1234)
      val (r1, state1) = state0.nextInt
      val (r2, state2) = state1.nextInt
      // etc.
      val (x, _) = state1.nextInt
      assert (x == r2)
      

      【讨论】:

        【解决方案4】:

        一个递归函数,派生自基于@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) )
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多