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?
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.
Related
I have the following code which grabs two pages of data from a paginated API endpoint. I'd like to modify query function to keep getting pages until it finds no more data (so replace take 2 in the code below with something which looks at the API response).
My question is wether it is possible to achieve this without changing query function to an IO function. And if so, how would I go about it. If not, is there a way of doing this without writing recursive function?
Here is the code:
#!/usr/bin/env stack
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import Servant.Client
import Network.HTTP.Client (newManager, defaultManagerSettings)
import Data.Proxy
import Servant.API
import Data.Aeson
import GHC.Generics
-- data type
data BlogPost = BlogPost
{ id :: Integer
, title :: String
} deriving (Show, Generic)
instance FromJSON BlogPost
-- api client
type API = "posts" :> QueryParam "_page" Integer :> Get '[JSON] [BlogPost]
api :: Proxy API
api = Proxy
posts :: Maybe Integer -> ClientM [BlogPost]
posts = client api
-- query by page
query :: ClientM [[BlogPost]]
query = sequence $ take 2 $ map posts pages
where
pages = [Just p | p <- [1..]]
-- main
main :: IO ()
main = do
manager' <- newManager defaultManagerSettings
let url = ClientEnv manager' (BaseUrl Http "jsonplaceholder.typicode.com" 80 "")
posts' <- runClientM query url
print posts'
I've tried to use takeWhileM to do this and ended up making query an IO function and passing url into it. It was starting to look pretty horrible and I couldn't get the types to match up (I felt like I needed something more like (a -> m Bool) -> m [a] -> m [a] rather than (a -> m Bool) -> [a] -> m [a] which is what takeWhileM is - still find this strange because I see this function as a filter, yet the input list and output list are different (one has monad around it and the other doesn't)).
For these cases of monadic iteration I usually turn to the streaming library. Its interface is reminiscent to that of pure lists, while still allowing effects:
import Streaming
import qualified Streaming.Prelude as S
repeatAndCollect :: Monad m => m (Either a r) -> m [a]
repeatAndCollect = S.toList_ . Control.Monad.void . S.untilRight
repeatAndCollectLimited :: Monad m => Int -> m (Either a r) -> m [a]
repeatAndCollectLimited len = S.toList_ . S.take len . S.untilRight
Using the untilRight, take and toList_ functions.
When only the first successful result is needed, we can use the Alternative instance of the ExceptT transformer in combination with asum from Data.Foldable to execute a list of fallible actions until one of them succeeds.
IO itself has an Alternative instance that returns the first "success", where "failure" means throwing a IOException.
Have you tried unfoldM?
unfoldM :: Monad m => m (Maybe a) -> m [a]
Let's update posts this way
posts :: Maybe Integer -> ClientM (Maybe [BlogPost])
posts = fmap notNil . client api where
notNil [] = Nothing
notNil bs = Just bs
The idea is to update query so that you can just use unfoldM query and get back an ClientM [[BlogPost]]. To do that, the type of query has to be
query :: ClientM (Maybe [BlogPost])
meaning, the page number must be coming from the environment:
query = forever $ page >>= posts
Clearly, there is some form of state going on here, as we need a way to keep track of the current page number. We can wrap the client action in a StateT:
type ClientSM = StateT Integer ClientM
page :: ClientSM Integer
page = get <* modify (+1)
This action demands a few additional changes to both query and posts. Edit: see below for a stroke of insight I got in the bus. First we need to lift the client action in the state monad:
posts :: Integer -> ClientSM (Maybe [BlogPost])
posts = fmap notNil . lift . client api . Just where
notNil [] = Nothing
notNil xs = Just xs
Only the type of query needs changing
query :: ClientSM (Maybe [BlogPost])
Finally, the main action just needs to peel the monad stack and unfold the query:
main = do
manager' <- newManager defaultManagerSettings
let url = mkClientEnv manager' (BaseUrl Http "jsonplaceholder.typicode.com" 80 "")
result <- flip runClientM url $ flip runStateT 1 $ unfoldM query
case result of
Left error -> print error
Right (posts, _) -> print posts
I haven't tested this, but it compiles 😅🤗
posts is oblivious to the state, and should remain so. So, without changing my original version above, you just need to lift in query:
query :: ClientSM (Maybe [BlogPost])
query = forever $ page >>= lift . posts . Just
If you need to keep the ClientM objects separate (either to run them each in a clean state, or anything similar), the best way is to chain your operations together.
In this particular case, the runClientM query ... IO action returns a Either String [BlogPost]. This means that the stop condition is receiving a Left String from one of the computations.
Using a hand-crafted eitherM helper, which runs one of two actions depending on the Either contructor, here is a relatively simple example of that:
Using the good old either makes this relatively simple :
queryAll :: ClientEnv -> [Int] -> IO [[BlogPost]]
queryAll _ [] = return []
queryAll url (x:xs) = runClientM (posts x) url >>= either ((const.pure) []) (\b -> (b:) <$> queryAll url xs)
main :: IO ()
main = do
manager' <- newManager defaultManagerSettings
let url = ClientEnv manager' (BaseUrl Http "jsonplaceholder.typicode.com" 80 "")
posts' <- queryAll url [1..]
print posts'
Hope it can help! :)
I want to handle/store random generator(Gen (ST {..}) outside of ST monad, but I couldn't find how to do.
Background
I'm under working for some simulation which uses random heavily.
With profiling, I knew that make random numbers takes more than 50% of process time.
To make random number, I use mwc-random and SFMT.
Because of speed issue, I mainly use SFMT.
However, comeparing with SFMT, mwc-random have richer interfaces that I need(like normal, bernoulli, ..).
After benchmark and read codes, I understand that mwc-random is not too slow than SFMT when it is used on ST monad.
(SFMT on IO < MWC on ST << MWC on IO < SFMT on ST)
So, I want to make and handle MWC random generator on ST monad.
However, I cannot take this generator out from ST monad as same as other ST things(e.g. STRef).
Problem
Is there any way to handle/store this random generator outside of ST monad safely?
I tried to study from many packages/codes with STRef or something others, but I couldn't figure it out.
Example
I use random generator in the simulation like this way.
import qualified System.Random.MWC as MWC
import GHC.Prim
import Control.Monad
data World = World { randomGen :: MWC.Gen RealWorld }
initWorld = do gen <- MWC.create
return $ World gen
something gen = do num <- MWC.uniformR (1,100) gen :: IO Int
print num
main = do world <- initWorld
replicateM_ 100 $ something (randomGen world)
But, this code does not works.
import qualified System.Random.MWC as MWC
import Control.Monad
import Control.Monad.Primitive
import Control.Monad.ST
data World s = World { randomGen :: MWC.Gen (PrimState (ST s))}
initWorld :: ST s (World s)
initWorld = do gen <- MWC.create
return $ World gen
something gen = do
let num :: Int
num = runST $ do num <- MWC.uniformR (1,100) gen
return num
print num
main = do let world = runST initWorld
replicateM_ 100 $ something (randomGen world)
I want rewrite this code to work with something.
Do I need to define/rewrite data structure or do something other?
Is there more smart way?
Points:
I need to handle a random generator (like Gen (PrimState (ST s))) to reproduce results.
So, I do not want to produce ad-hoc random generator.
I do not wants to save/restore seed. It has too big overhead.
(save/restore seed takes x12~15 time more than generate one random number)
It is slower than using on IO monad, so I do not need to do on ST monad.
I do not want to use unsafe* functions.
You shouldn't try to manipulate the generator outside of the ST monad. Because of the type of runST, trying to use things which live "inside" the state thread "outside" of it is non-nonsensical. Imagine you had a function of the following type (which is the function you are trying to write):
something :: MWC.Gen s -> Int
something gen = runST ...
In order to generate random numbers, some stateful computations must be done with the data inside of the Gen. At which point will those computations be done? How many times will they be done, if at all? Most importantly - how can something be generating random numbers - it is a pure function, after all, so it must return the same value for the same input.
Instead, you should thread the state along, and call runST at the end:
something :: MWC.Gen s -> ST s Int
something = MWC.uniformR (1,100)
main = mapM_ print $ runST $ do
w0 <- initWorld
replicateM 100 (something $ randomGen w0)
I'm currently trying to encrypt a message (String) with the help of a random generated number in Haskell. The idea is to get the message, generate a random String of numbers with the same length (or more and then to take the length I need).
Then i want to perform some actions based on the ASCII representation and then return the encrypted String.
Unfortunately I'm not very versed with monads in Haskell, so it might be a very simple problem to solve, which I can't comprehend yet.
generateMyKey string = newStdGen >>= \x -> print $ concatMap show $ map abs $ rs x
where rs x = randomlist (length string) x
randomlist :: Int -> StdGen -> [Int]
randomlist n = take n . unfoldr (Just . random)
So the problem is I get an IO() out of getMyKey, but I want to have a String, or atleast a IO(String) to perform the encrypting mechanism.
Right now I'm getting a big list of positive (hence the abs + map) random numbers, but I can't access them.
There are two basic ways to go about this (and one more complicated but easier). If you're just using System.Random, you can generate random numbers in two ways, either by accepting a StdGen and staying pure, or using the OS's random generator and staying in IO. At some point, you'll have to make a call to the OS's random functionality to get a seed or value, but this can happen in main far away from your actual code.
To keep your functions pure, you'll need to pass around a StdGen and use the functions
random :: Random a => StdGen -> (a, StdGen)
randoms :: Random a => StdGen -> [a]
(Note: I've substituted RandomGen g => g for StdGen, there's no need to write a custom RandomGen instance for your case)
You can then write your function generateMyKey as
randomList :: Int -> StdGen -> [Int]
randomList n = take n . randoms
generateMyKey :: String -> StdGen -> String
generateMyKey text g
= concatMap show
$ map abs
$ randomList (length text) g
And this entirely avoids having to live in IO. Be wary, though, if you re-use the same g, you'll generate the same random list each time. We can avoid this by using IO and its related functions
randomList :: Int -> IO [Int]
randomList 0 = return []
randomList n = do
first <- randomIO
rest <- randomList (n - 1) -- Recursively generate the rest
return $ first : rest
generateMyKey :: String -> IO String
generateMyKey text = do
key <- randomList (length text)
return $ concatMap show $ map abs $ key
This will come with a performance hit, and now we've lost the ability to generate the same key repeatedly, making it difficult to test our functions reliably! How can we reconcile these two approaches?
Enter the package MonadRandom. This package provides a monad (and monad transformer, but you don't need to worry about that right now) that lets you abstract away how you generate random numbers so that you can choose how you want to run your code in different circumstances. If you want IO, you can use IO. If you want to supply a seed, you can supply a seed. It's very handy. You can install it with cabal install MonadRandom and use it as
import Control.Monad.Random
randomList :: Int -> Rand StdGen [Int]
randomList n = fmap (take n) getRandoms
generateMyKey :: String -> Rand StdGen String
generateMyKey text = do
key <- randomList (length text)
return $ concatMap show $ map abs $ key
Our generateMyKey code is even the same as the IO version other than the type signature!
Now to run it.
main :: IO ()
main = do
-- Entirely impure, have it automatically grab a StdGen from IO for us
ioVersion <- evalRandIO $ generateMyKey "password"
-- Make a StdGen that stays the same every time we run the program, useful for testing
let pureStdGen = mkStdGen 12345
pureVersion = evalRand (generateMyKey "password") pureStdGen
-- Get a StdGen from the system, but still evaluate it purely
ioStdGen <- getStdGen
let pureVersion2 = evalRand (generateMyKey "password") ioStdGen
-- Print out all three versions
putStrLn ioVersion
putStrLn pureVersion
putStrLn pureVersion2
There are a number of solutions to this problem, but at first glance it might seem that you need to have your entire program operate in the IO monad, but you don't! The entry (/exit) point of your program is the only place that needs to see IO -- you can factor out any transformations on your random list into pure functions, i.e:
import Data.List
import System.Random
generateMyKey :: String -> IO String
generateMyKey string = do
x <- newStdGen
let rs = randomlist (length string)
return $ concatMap show $ map abs $ rs x
randomlist :: Int -> StdGen -> [Int]
randomlist n = take n . unfoldr (Just . random)
change :: String -> String
change = reverse -- for example
main :: IO ()
main = do
key <- generateMyKey "what"
putStrLn $ change key
generateMyKey is identical to what you had before, except that it's written in do notation now and is returning the string instead of just printing it. This allows us to "pull out" a random key from inside the IO monad and transform it with regular pure functions, like change, for example. This allows you to reason about the pure functions as normal, while still pulling in your values from IO.
This question is close to ground covered elsewhere, but I haven't found anything that addresses it specifically (at least not in a way that I'm able to understand).
I'd like to update state in a way that depends on various random choices. Because of the instance of the RandomSource typeclass that I'm using, all of these random choices live in the IO monad, as below:
main :: IO Int
main = do
a <- pickRand [1..7]
return a
where pickRand lst = runRVar (choice lst) DevRandom
What I'd like to do is something like the following: store a state of type [Int], and if the randomly chosen list element a is greater than 3 , push it onto the state. Any tips?
import Control.Monad
import Control.Monad.Trans.State
import Control.Monad.IO.Class
import Data.Random.RVar
import Data.Random.Source.DevRandom
import Data.Random.List
myFun :: StateT [Int] IO ()
myFun = do
lst <- get
r <- liftIO $ runRVar (randomElement lst) DevRandom
put $ if r > 3 then (r:lst) else lst
return ()
main :: IO ()
main = evalStateT myFun [1..10] >>= print
I have the following code:
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.State
type T = StateT Int IO Int
someMaybe = Just 3
f :: T
f = do
x <- get
val <- lift $ do
val <- someMaybe
-- more code in Maybe monad
-- return 4
return 3
When I use do notation inside to work in Maybe monad it fails. From the error it gives it looks like type signature for this do doesn't match. However I have no idea how to fix it. I tried some lift combinations, but none of them worked and I don't want to guess anymore.
The problem is that Maybe is not part of your transformer stack. If your transformer only knows about StateT Int and IO, it does not know anything about how to lift Maybe.
You can fix this by changing your type T to something like:
type T = StateT Int (MaybeT IO) Int
(You'll need to import Control.Monad.Trans.Maybe.)
You will also need to change your inner do to work with MaybeT rather than Maybe. This means wrapping raw Maybe a values with MaybeT . return:
f :: T
f = do
x <- get
val <- lift $ do
val <- MaybeT $ return someMaybe
-- more code in Maybe monad
return 4
return 3
This is a little awkward, so you probably want to write a function like liftMaybe:
liftMaybe = MaybeT . return
If you used lift to lift IO a values in other parts of your code, this will now break because you have three levels in your transformer stack now. You will get an error that looks like this:
Couldn't match expected type `MaybeT IO t0'
with actual type `IO String'
To fix this, you should use liftIO for all your raw IO a values. This uses a typeclass to life IO actions through any number of transformer layers.
In response to your comment: if you only have a bit of code depending on Maybe, it would be easier just to put the result of the do notation into a variable and match against that:
let maybeVal = do val <- someMaybe
-- more Maybe code
return 4
case maybeVal of
Just res -> ...
Nothing -> ...
This means that the Maybe code will not be able to do an IO. You can also naturally use a function like fromMaybe instead of case.
If you want to run the code in the inner do purely in the Maybe monad, you will not have access to the StateT Int or IO monads (which might be a good thing). Doing so will return a Maybe value, which you will have to scrutinize:
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.State
type T = StateT Int IO Int
someMaybe = Just 3
f :: T
f = do
x <- get
-- no need to use bind
let mval = do
-- this code is purely in the Maybe monad
val <- someMaybe
-- more code in Maybe monad
return 4
-- scrutinize the resulting Maybe value now we are back in the StateT monad
case mval of
Just val -> liftIO . putStrLn $ "I got " ++ show val
Nothing -> liftIO . putStrLn $ "I got a rock"
return 3