Question

I have a simple little Happstack application that shows a form with an email field and a random question field to help combat spam. To get a random number I use getStdGen in my main function and pass it along to my function which creates the html. The problem is that the same StdGen is used so my random value is not random unless I restart the application.

Here's what my Main.hs looks like:

{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}                                                                                                

module Main where                                                                                                                                      

import Happstack.Lite                                                                                                                                  
import qualified Pages.Contact as Contact                                                                                                                                                                                                                                
import System.Random                                                                                                                                   

main :: IO ()                                                                                                                                          
main = do                                                                                                                                              
    gen <- getStdGen                                                                                                                                   
    serve Nothing $ pages gen                                                                                                                          

pages :: StdGen -> ServerPart Response                                                                                                                 
pages g = msum                                                                                                                                         
    [ dir "contact" $ Contact.page g                                                                                                                   
    ... Other irrelevant pages                                                                                                           
    ]

And here's the function that uses the StdGen to retrive a random question id:

getRandomQID :: StdGen -> Int                                                                                                             
getRandomQID g =                                                                                                                                       
    let (rpercent, _) = random g :: (Float, StdGen)                                                                                                    
        rid           = rpercent * questionsAmount                                                                                                    
    in  round rid                                                                                                                

questionsAmount :: (Num a) => a                                                                                                                        
questionsAmount = (fromIntegral . length) questions

What is the most elegant way to solve this problem?

Was it helpful?

Solution

As I wrote this question I found a solution that worked in the Happstack crash course (templates).

In your route which has a return type of ServerPart Response you can use the liftIO monad transformer to be able to perform IO actions. There's this handy function called randomRIO with generates a random Int from an input of a tuple which two Ints as range, like this:

page :: ServerPart Response
page = do 
    randID <- liftIO $ randomRIO (0, max)
    ... Code to generate response ...
    where max = length questions

randomRIO can be found in System.Random and liftIO can be found in Control.Monad.Trans.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top