Search code examples
haskellfrpyampa

How to let a random amount of time pass with Yampa


I'm trying to write a simple FRP sample with Yampa that instead of waiting for 2 seconds (like here: https://wiki.haskell.org/Yampa/reactimate) will wait for a random amount of time within some bounds. I have tried multiple different approaches to somehow get the randomRIO function into the signal function but can't realy grasp what I am supposed to do. My intention is to replace the twoSecondsPassed function somewhat like this:

randomTimePassed :: SF () Bool
randomTimePassed = time >>> arr (\x -> x < randomRIO (0, 10))

but this doesn't seem to do the trick because of a type missmatch. The compiler outputs:

* Couldn't match type `m0 a0' with `Double'
  Expected: SF Time Bool
    Actual: SF (m0 a0) Bool
* In the second argument of `(>>>)', namely
    `arr (\ x -> x < randomRIO (0, 10))'
  In the expression: time >>> arr (\ x -> x < randomRIO (0, 10))
  In an equation for `randomTimePassed':
      randomTimePassed = time >>> arr (\ x -> x < randomRIO (0, 10))

Any pointers in the right direction would be greatly appreciated as I'm very new to Yampa and can't seem to find a proper documentation to help me out.


Solution

  • The type of randomRIO (0,10) is (specialized as you're using it) IO Double, but the type of 2, which you're replacing, is simply Double. Furthermore, you can't do IO actions from within a yampa SF.

    What you'll need to do is generate your number (or perhaps generate a generator for your number) outside of the SF and pass it in as an argument. For instance, you can write:

    someTimePassed :: Double -> SF () Bool
    someTimePassed t = time >>> arr (\x -> x < t)
    
    main = do
      t <- getCurrentTime
      timeRef <- newIORef t
      randTime <- randomRIO (0, 10)
      reactimate initialize (sense timeRef) actuate (someSecondsPassed randTime)
    

    If you're going to need multiple random numbers, you'll want to pass a random number generator. You can generate one using, for instance getStdGen. Furthermore, rather than writing your own SF to use it, you could pass it to something like occasionally, which produces events every so often.