Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Random Generator ... how to make easier to use?

Tags:

random

haskell

I am with trouble related to Haskell Random generator. At university, i have to deal with Java all my way around, so now I'm, corrupted with it. I am developing a game in Haskell, and now I face something like 'chance to do something', and that chance needs to be like Int -> Bool. In Java, I would have done

new Random().nextInt(100) 

and there, problem solved! In Haskell I have to choose something in a monad IO or something with a seed. None of these does what I want. I don't really want to use IO monad in my pure model, and the seed is awkward to use because I need to remember my new seed every time...

Is there something simple like Java's Random?

like image 621
Illiax Avatar asked Sep 07 '11 05:09

Illiax


4 Answers

Believe it or not, you'll have to use different approaches in Haskell than you did in Java. There are a couple packages that can help you, but you will have to get a different attitude in your head to use them successfully. Here are some pointers:

  • http://hackage.haskell.org/package/MonadRandom to painlessly track seeds
  • http://hackage.haskell.org/package/mwc-random for high-speed, high-quality randomness
  • http://hackage.haskell.org/package/comonad-random for another approach to wrapping up seeds, in case you would prefer comonads to monads

Searching for the word "random" on Hackage's package list will turn up many, many more specific packages for more specific needs.

like image 104
Daniel Wagner Avatar answered Oct 19 '22 13:10

Daniel Wagner


Sorry, but you will have to live with that. How can there be a function in a pure functional language that gives you different values on each call? Answer is: it cannot - only in the IO-Monad or something similiar like the state-monad where you can pass your seed around (and don't have the same input every time) can such a things exist.

You may alsow have a look as this question "How can a time function exist in functional programming?" as it's in the same direction as yours.

like image 39
Random Dev Avatar answered Oct 19 '22 11:10

Random Dev


I think, "you will have to live with that", is neither useful nor correct. It really depends on the abstractions you are using. If your application is naturally bound to a monad, then it makes sense to use a monadic random number generator, which is just as convenient as Java's random number generator.

In the case of a game using modern abstractions your application is naturally bound to functional reactive programming (FRP), where generating random numbers is no problem at all and doesn't require you to pass around generators explicitly. Example using the netwire library:

movingPoint :: MonadIO m => (Double, Double) -> Wire m a (Double, Double)
movingPoint x0 =
    proc _ -> do
        -- Randomly fades in and out of existence.
        visible <- wackelkontakt -< ()
        require -< (visible, ())

        -- 'rnd' is a random value between -1 and 1.
        rnd <- noise1 -< ()

        -- dx is the velocity.
        let dx = (sin &&& cos) (rnd * pi)

        -- Integration of dx over time gives us the point's position.
        -- x0 is the starting point.
        integral x0 -< dx

Is there any way to express this easier and more concisely? I guess not. FRP also proves Zhen's comment wrong. It can handle user input purely.

like image 3
ertes Avatar answered Oct 19 '22 13:10

ertes


It is somewhat unintuitive that something that neither does input nor output needs to be handled as if it had. Let's say you defined it as follows:

random100 = unsafePerformIO $ randomRIO (1, 100) -- This will not work!

That would indeed give you a random number - in a way. What you truly need is a way to encode that you want a new pseudo-random number every time. This means information needs to go from one random number generation to the next. Most languages just ignore this "minor detail", but Haskell forces you to pay attention. You might thank Haskell when you find yourself in the spot to properly reproduce your pseudo-random result in a multi-threaded context.

There's a number of ways you can make these connections, most of which have been mentioned already. If you are reluctant to use a monad: Note that it might generally be a good thing to have your code in a monadic form (but not using IO!). Down the road, you might well come into situations where you want more monad features, such as a reader for configuration - then all ground work would be done already.

like image 2
Peter Wortmann Avatar answered Oct 19 '22 13:10

Peter Wortmann