giuseppe maugeri
giuseppe maugeri

Reputation: 159

Generate random number with no side effect

Recentely I began to study functional programming paradigm using Scala as reference language. I come up with this problem: How to generate a random number with no side effect ? Googling I found this solution:

package fp.crazy-bankers.utils

    object Rng {
        def next(seed : Int) : (Int,Int) = {
            val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0x FFFFFFFFFFFFL
            val number = (newSeed >>> 16).toInt
            (newSeed, number)
        }
    }

Basically here the state (the seed) is managed passing it explicitly on every invocation of next method. This implementation works for me until I call it from the same place because in this way is easy to keep care of the state and pass it on each invocation.

But what if I need a random number in different places? For example if I call next method from 10 different actors, in this case each actor is able to pass its local copy of the state only.

Basically in this way there is no global knowledge of the state across all actors,so risks is different actors get the same random number. How to solve this issue?

Have I to find someway to manage globally the state or try with a completely different pattern?

Upvotes: 1

Views: 745

Answers (4)

Matthias Berndt
Matthias Berndt

Reputation: 4587

You can share mutable state between different places using the Ref construct. There are several implementations of it in Scala:

ZIO Ref: https://zio.dev/docs/datatypes/datatypes_ref

cats-effect Ref: https://typelevel.org/cats-effect/docs/2.x/concurrency/ref

However this requires you to pass the Ref explicitly to every place that is going to use it. This is a feature, not a bug, because it makes it easier to identify all the places where some piece of mutable state is used – there is no way to have global mutable state.

But since you mentioned actors, I doubt that you're really doing pure FP anyway. There's basically no way to do that at least with Akka, because even sending a message between actors is a side effect.

Upvotes: 3

Tim
Tim

Reputation: 27421

If you want to "use a purely functional design style" then you have to pass a seed to every function that requires "random" numbers. There is no other choice. All other options require a side-effect or lose referential transparency.

So if you use random numbers in multiple functions, you have to provide a different seed to each of those functions.

The seed is just a compact way of representing an infinite sequence of random numbers, so an alternative is to generate the random numbers outside the function and past the values to the function rather than the seed.

Upvotes: 2

phipsgabler
phipsgabler

Reputation: 20960

You use a different type of PRNG, that supports splitting. Then you split the generator on the main actor as many times as you need, and send one subgenerator to each of the other actors.

As an example, JAX does this by using a generator called threefry.

Upvotes: 2

Dmytro Mitin
Dmytro Mitin

Reputation: 51693

You can introduce a separate actor that will reply with next random number.

For example actors will send GetNextRandomNumber to this actor and it will reply NextRandomNumber(number).

This actor will manage its state (seed) itself.

Actually sending a message to this actor will be a side effect.

Normally generating a random number is a side effect because function that is free of side effects can't produce different outputs on the same input.

The idea of functional programming is not to avoid side effects but to control them. For example with IO, State etc.

Upvotes: 3

Related Questions