Search code examples
randomelm

How can I get a random value in a range determined by a signal?


First some code:

import Random
import Window

writeRandom x = lift asText (Random.range 0 x <| every second)

upperLimit = 300
-- upperLimit = Window.width -- How can i use this instead?

main = writeRandom upperLimit

Ultimately I'm trying to get random points on the screen, but I can't figure out how to pass Window.height and Window.width to Random.range. I don't think I can 'lift' Random.range, since it already returns a signal. If I try I get a type error:

Type Error: 'main' must have type Element or (Signal Element).
Instead 'main' has type:

   Signal (Signal Element)

And I'm not sure that the opposite of lift (lower?) exists, or even makes sense.

Thanks


Solution

  • You are correct in supposing that an opposite of lower doesn't make sense.
    In this particular case, the builtin Random library is builtin because it's a wrapper around a native JavaScript call. This is the reason for the Signal return type, to keep the code pure. And even then, it's not completely well-behaved.

    To get the kind of random range you want, you'll need a different random number generator. There is a community library that was published only a few days ago, that'll probably answer your needs. You can check it out of GitHub yourself, or use the elm-get tool.

    Your code would become something like (untested!):

    import Window
    import Generator
    import Generator.Standard as GStd
    
    randomSeed = 12346789
    
    writeRandom : Signal Int -> Signal Element
    writeRandom x = 
      let update high (_, gen) = Generator.int32Range (0,high) gen
          start = (0, GStd.generator randomSeed)
          input = sampleOn (every second) x
          result = fst <~ foldp update start input
      in  lift asText result
    
    upperLimit = Window.width
    
    main = writeRandom upperLimit
    

    In writeRandom, you use foldp to keep the latest random-number generator. In update you use this to get a new random number and a new generator for the next time. The input of x is updated every second by using sampleOn (every second). The fst <~ part is to remove the random number generator, since you only want the random number.