1

This is a follow-up to my previous question

Suppose I have a RandomGen[A] monad. This is actually a function: Long => (Long, A) with map and flatMap and another function certain to create a new instance of RandomGen (as return in Haskell)

class RandomGen[A](run: Long => (Long, A)) {

  def apply(seed: Long) = run(seed)

  def flatMap[B](f: A => RandomGen[B]): RandomGen[B] =
    new RandomGen(seed => {val (seed1, a) = run(seed); f(a)(seed1)})

  def map[B](f: A => B): RandomGen[B] =
    new RandomGen(seed => {val (seed1, a) = run(seed); (seed1, f(a))})
}

def certain[A](a: A): RandomGen[A] = new RandomGen(seed => (seed, a))

Suppose also I have a generator of random bits

def nextbits(bits: Int): RandomGen[Int] = ...

Now I would like to add new generator that yields random numbers between 0 and a given n. I copied the implementation from java.util.Random and omitted the special case where n is a power of two for simplicity.

def integer(n: Int): RandomGen[Int] = 
  nextbits(31).flatMap {r =>
    val value = r % n
    if (r - value + (n -1) < 0) integer(n) else certain(value)
  }

Does it make sense ?

Community
  • 1
  • 1
Michael
  • 41,026
  • 70
  • 193
  • 341

1 Answers1

1

Yes. Note that this is just the State monad, so you could reuse the scalaz implementation of that if you like. Also you could use map instead of flatMap and avoid needing to call certain.

lmm
  • 17,386
  • 3
  • 26
  • 37
  • I did not figure out how to use `map` i/o `flatMap`. Could you show a code to do that ? – Michael Dec 17 '14 at 09:27
  • Oh, my mistake, I missed the recursion, no, the `flatMap` approach is good. – lmm Dec 17 '14 at 10:00
  • Is it possible to rewrite the `integer` above with _for-comprehension_ ? – Michael Dec 17 '14 at 10:22
  • Yes, it's possible, but since you only have one `flatMap` I don't think it would be worth it. `for` comprehensions are great for expressing a long chain of `flatMap` calls and avoiding the "pyramid of doom" effect. – lmm Dec 17 '14 at 11:13