Happstack получает новый StdGen для каждого запроса?

У меня есть простое небольшое приложение Happstack, которое показывает форму с полем электронной почты и полем случайного вопроса для борьбы со спамом. Чтобы получить случайное число, я использую getStdGen в своей функции main и передаю его своей функции, которая создает html. Проблема в том, что используется одно и то же StdGen, поэтому мое случайное значение не является случайным, если я не перезапущу приложение.

Вот как выглядит мой Main.hs:

{-# 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                                                                                                           
    ]

А вот функция, которая использует StdGen для получения случайного идентификатора вопроса:

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

Какой самый элегантный способ решить эту проблему?


person rzetterberg    schedule 15.06.2013    source источник


Ответы (1)


Когда я писал этот вопрос, я нашел решение, которое сработало, в интенсивном курсе Happstack (шаблоны). .

В вашем маршруте с типом возврата ServerPart Response вы можете использовать монадный преобразователь liftIO, чтобы иметь возможность выполнять действия ввода-вывода. Есть удобная функция randomRIO, которая генерирует случайный Int из входных данных кортежа, в котором два Int являются диапазоном, например:

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

randomRIO можно найти в System.Random, а liftIO можно найти в Control.Monad.Trans.

person rzetterberg    schedule 15.06.2013