picking a random element from a list - haskell

So in a project of my I have a constant function that returns an array :
import System.Random
giveList :: [Int]
giveList = [8,9,4,5,2]
and I would like to randomly select an element from that list like this:
seed::Int
seed = 40
generator = mkStdGen seed
giveRandomElement :: Int
giveRandomElement = giveList !! rand where
n = length tetrominoes
(rand,generator) = randomR (0,(n-1)) generator
However, this does not compile because of the generator, I would like to keep the generator as a global variable so I don't have to keep giving it to functions.
I also don't want to deal with IO wrappers, so in what way can I do this ?
Thx for the help :-)

A working code example
import System.Random
seed::Int
seed = 40
giveList :: [Int]
giveList = [8,9,4,5,2]
generator = mkStdGen seed
giveRandomElement :: Int
giveRandomElement = giveList !! rand where
n = length giveList
(rand, _) = randomR (0,(n-1)) generator
But that probably doesn't do, what you want.
giveRandomElement will always yield the same result. It is a pure function without any inputs, so what should it do? It can only be constant.
You either need to use IO or you need to thread your generator through your code and keep track of it somewhere.
The compiler error you got:
test.hs:14:23: error:
• Ambiguous type variable ‘g0’ arising from a use of ‘randomR’
prevents the constraint ‘(RandomGen g0)’ from being solved.
Relevant bindings include generator :: g0 (bound at test.hs:14:10)
Probable fix: use a type annotation to specify what ‘g0’ should be.
These potential instance exist:
instance RandomGen StdGen -- Defined in ‘System.Random’
• In the expression: randomR (0, (n - 1)) generator
In a pattern binding:
(rand, generator) = randomR (0, (n - 1)) generator
In an equation for ‘giveRandomElement’:
giveRandomElement
= giveList !! rand
where
n = length giveList
(rand, generator) = randomR (0, (n - 1)) generator
|
14 | (rand, generator) = randomR (0,(n-1)) generator
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
was because you defined the symbol generator in giveRandomElement in terms
of it self and so the compiler couldn't deduce its type. (The top level declaration generator wasn't used in that case, because (rand, generator) = already shadowed the symbol after the equal sign.

I would like to keep the generator as a global variable so I don't have to keep giving it to functions. I also don't want to deal with IO wrappers, so in what way can I do this ?
Sorry, a function giveRandomElement :: Int that returns a different random number every time you call it isn't referentially transparent, so Haskell's purity does not allow you to do what you'd like.
I think working with random values is a great opportunity to learn about monads. MonadRandom has a very flexible interface for writing functions whose results are random:
die :: (MonadRandom m) => m Int
die = getRandomR (1, 6)
rollDice :: (MonadRandom m) => m (Int, Int)
rollDice = do
x <- die
y <- die
return (x, y)
-- Your example
giveRandomElement :: (MonadRandom m) => m Int
giveRandomElement = do
let n = length tetrominoes
i <- getRandomR (0, n-1)
return (giveList !! i)
The implementations of this monad will thread the randomness state through your random functions for you. There's even an instance MonadRandom IO, which lets you write
main :: IO ()
main = do
x <- giveRandomElement
print x

Related

Unpacking and printing values from State-Monad in Haskell using get

I am trying to get a good grasp of the State-Monad (and Monads in general) but I am struggling with rewriting the below function using the state Monad and the do-notation, which resulted as an exercise for me propose here
import Control.Monad
import System.Random
import Data.Complex
import qualified System.Random as R
import Control.Monad.Trans.State.Lazy
giveRandomElement :: [a] -> State R.StdGen a
giveRandomElement lst = do
let n = length lst
rand <- state $ randomR (0, n-1)
return $ lst !! rand
random_response_monad :: a -> [a] -> State R.StdGen a
random_response_monad true_answer answers = do
tal <- state $ randomR (0, 1) :: StateT StdGen Data.Functor.Identity.Identity a
if (tal == 0) then true_answer
else giveRandomElement answers
As is immediately obvious there are some type problems for the tal-variable as it occurs in the if-clause and the first line of the do-expression. As is visible from the code I have tried to force the latter by a specific type in order to make it unambiguous and clearer for myself as well. I have done so by the compiler-suggestion I got when I first tried to force it to be of the Int-type. I Am however not able to use that value in an if-statement, and I am unsure of how to convert or unpack the value such that I get it as an Int.
So far I have tried to add the folloowing line after tal <- ... , resp <- get $ tal but I get this output.
error:
* Couldn't match expected type: t0
-> StateT StdGen Data.Functor.Identity.Identity a1
with actual type: StateT s0 m0 s0
* The first argument of ($) takes one value argument,
but its type `StateT s0 m0 s0' has none
In a stmt of a 'do' block: resp <- get $ tal
In the expression:
do tal <- state $ randomR (0, 1)
resp <- get $ tal
if (resp == 0) then
giveRandomElement answers
else
giveRandomElement answers
* Relevant bindings include tal :: t0
Furthermore I am baffled what would be the best way to 'print' the result returned by giveRandomElement as the type is based on the type declared for the State-monad which as I understand it doesn't use the deriving Show also. But this can perhaps be solved by unpacking the value as enquired about above.
EDIT
I used the above packages although they are probably not all used in the above code. I am unsure of which is used by the code by I suspect the qualified System.Random as R
The following code line:
tal <- state $ randomR (0, 1) :: StateT StdGen Data.Functor.Identity.Identity a
is quite long and might cause a horizontal slider to appear, at least on my platform.
So it is all too easy to overlook that at its very end, the a type variable is used, while it should be just Int.
Also, the two branches of the if construct use different types, making the construct ill-typed. The then branch gives a pure a value, while the else branch gives a monadic value. This is easily fixed by changing to:
if (tal == 0) then return true_answer
as the (slightly misnamed) return library function wraps its argument into the monad at hand.
The following code, which tries to keep code lines short enough, seems to work fine:
import Control.Monad.State
import qualified System.Random as R
import qualified Data.Functor.Identity as DFI
giveRandomElement :: [a] -> State R.StdGen a
giveRandomElement lst = do
let n = length lst
rand <- state $ R.randomR (0, n-1)
return $ lst !! rand
type ActionType = StateT R.StdGen DFI.Identity Int
random_response_monad :: a -> [a] -> State R.StdGen a
random_response_monad true_answer answers = do
tal <- (state $ R.randomR (0, 1) :: ActionType)
if (tal == 0) then return true_answer
else giveRandomElement answers
main :: IO ()
main = do
let g0 = R.mkStdGen 4243
action = random_response_monad 20 [0..9]
(k, g1) = runState action g0
putStrLn $ "k is set to: " ++ (show k)
Side note: the code can also be made to compile without the complex type annotation, like this:
tal <- state $ R.randomR (0::Int, 1)
Something like this seems to work:
random_response_monad :: a -> [a] -> State R.StdGen a
random_response_monad true_answer answers = do
tal <- state $ randomR (0 :: Int, 1)
if (tal == 0) then return true_answer
else giveRandomElement answers
Two changes:
Use a type annotation to tell the compiler what you mean by 0 and 1. Once you've told the compiler which type 0 is, it follows that 1 has the same type. (Keep in mind that in Haskell, numbers are polymorphic. Without more information, Haskell will see a literal such as 0 as potentially any Num instance.)
return in front of true_answer.
Here's a few samples from GHCi that seems to indicate that it works:
ghci> evalState (random_response_monad 42 [0..9]) <$> newStdGen
4
ghci> evalState (random_response_monad 42 [0..9]) <$> newStdGen
1
ghci> evalState (random_response_monad 42 [0..9]) <$> newStdGen
42

Couldn't match type ‘IO’ with ‘[]’

I wrote a function to generate two random numbers, which I then pass to a different function to use them there. The code for this is:
randomIntInRange :: (Int, Int, Int, Int) -> Board
randomIntInRange (min,max,min2,max2) = do r <- randomRIO (min, max)
r2 <- randomRIO (min2, max2)
randomCherryPosition (r, r2)
And the function this function calls in its 'do' block is:
randomCherryPosition :: (Int, Int) -> Board
randomCherryPosition (x, y) = initialBoard & element y . element x .~ C
Where initialBoard is a list of lists and C is a predefined data type. I am using lens to change values inside the list. Running this gives me the error:
Couldn't match type ‘IO’ with ‘[]’
Expected type: [Int]
Actual type: IO Int
for both r and r2 lines. I have absolutely no idea what is going on here, or what i'm doing wrong, so I would greatly appreciate any help.
randomRIO has type IO Int, not Int. As long as you use any IO functions, your surrounding function must also be in IO:
randomIntInRange :: (Int, Int, Int, Int) -> IO Board
randomIntInRange (min,max,min2,max2) = do r <- randomRIO (min, max)
r2 <- randomRIO (min2, max2)
pure $ randomCherryPosition (r, r2)
randomRIO is not a pure function. It returns a different value every time. Haskell bans such functions. There are numerous benefits that come from banning such functions, which I'm going to go into here. But you can still have such function if you wrap it in IO. The type IO Int means "it's a program that, when executed, will produce an Int". So when you call randomRIO (min, max), it returns you not an Int, but a program, which you can then execute to get an Int. You do the execution via the do notation with left arrow, but the result of that would also be a similar program.
Unfortunately there is no perfect solution to this problem. It has already been discussed on Stackoverflow, for example here.
The above solution provided by Fyodor involves IO. It works. The main drawback is that IO will propagate into your type system.
However, it is not strictly necessary to involve IO just because you want to use random numbers. An in-depth discussion of the pros and cons involved is available there.
There is no perfect solution, because something has to take care of updating the state of the random number generator every time you pick a random value. In imperative languages such as C/C++/Fortran, we use side effects for this. But Haskell functions have no side effects. So that something can be:
the Haskell IO subsystem (as in randomRIO)
yourself as the programmer - see code sample #1 below
a more specialized Haskell subsystem, for which you need to have: import Control.Monad.Random - see code sample #2 below
You can solve the problem without involving IO by creating your own random number generator, using library function mkStdGen, and then passing the updated states of this generator manually around your computations. In your problem, this gives something like this:
-- code sample #1
import System.Random
-- just for type check:
data Board = Board [(Int, Int)] deriving Show
initialBoard :: Board
initialBoard = Board [(0, 0)]
randomCherryPosition :: (Int, Int) -> Board
randomCherryPosition (x, y) = -- just for type check
let ls0 = (\(Board ls) -> ls) initialBoard
ls1 = (x, y) : ls0
in Board ls1
-- initial version with IO:
randomIntInRange :: (Int, Int, Int, Int) -> IO Board
randomIntInRange (min,max, min2,max2) = do r1 <- randomRIO (min, max)
r2 <- randomRIO (min2, max2)
return $ randomCherryPosition (r1, r2)
-- version with manual passing of state:
randomIntInRangeA :: RandomGen tg => (Int, Int, Int, Int) -> tg -> (Board, tg)
randomIntInRangeA (min1,max1, min2,max2) rng0 =
let (r1, rng1) = randomR (min1, max1) rng0
(r2, rng2) = randomR (min2, max2) rng1 -- pass the newer RNG
board = randomCherryPosition (r1, r2)
in (board, rng2)
main = do
-- get a random number generator:
let mySeed = 54321 -- actually better to pass seed from the command line.
let rng0 = mkStdGen mySeed
let (board1, rng) = randomIntInRangeA (0,10, 0,100) rng0
putStrLn $ show board1
This is cumbersome but can be made to work.
A more elegant alternative consists in using MonadRandom.
The idea is to define a monadic action representing the randomness-involving computation, and then to run this action using the aptly named runRand function.
This gives this code instead:
-- code sample #2
import System.Random
import Control.Monad.Random
-- just for type check:
data Board = Board [(Int, Int)] deriving Show
initialBoard :: Board
initialBoard = Board [(0, 0)]
-- just for type check:
randomCherryPosition :: (Int, Int) -> Board
randomCherryPosition (x, y) =
let ls0 = (\(Board ls) -> ls) initialBoard
ls1 = (x, y) : ls0
in Board ls1
-- monadic version of randomIntInRange:
randomIntInRangeB :: RandomGen tg => (Int, Int, Int, Int) -> Rand tg Board
randomIntInRangeB (min1,max1, min2,max2) =
do
r1 <- getRandomR (min1,max1)
r2 <- getRandomR (min2,max2)
return $ randomCherryPosition (r1, r2)
main = do
-- get a random number generator:
let mySeed = 54321 -- actually better to pass seed from the command line.
let rng0 = mkStdGen mySeed
-- create and run the monadic action:
let action = randomIntInRangeB (0,10, 0,100) -- of type: Rand tg Board
let (board1, rng) = runRand action rng0
putStrLn $ show board1
This is definitely less error prone than code sample #1, so you would typically prefer this solution as soon as your computations become complex enough. All the functions involved are ordinary pure Haskell functions, which the compiler can fully optimize using its usual techniques.

Haskell random numbers

I am trying to generate a sample of random numbers in Haskell
import System.Random
getSample n = take n $ randoms g where
g = newStdGen
but it seems I am not quite using newStdGen the right way. What am I missing?
First off, you probably don't want to use newStdGen. The biggest problem is that you'll get a different seed every time you run your program, so no results will be reproducible. In my opinion, mkStdGen is a better choice as it requires you to give it a seed. This means you will get the same sequence of (pseudo)random numbers every time. If you want a different sequence, just change the seed.
The second problem with newStdGen is that since it's impure, you'll end up in the IO monad which can be a bit inconvenient.
sample :: Int -> IO [Int]
sample n = do
gen <- newStdGen
return $ take n $ randoms gen
You can use do-notation to 'extract' the values and then sum them:
main :: IO ()
main = do
xs <- sample 10
s = sum xs
print s
Or you could 'fmap' the function over the result (but notice that at some point you will probably need to extract the value):
main :: IO ()
main = do
s <- fmap sum $ sample 10
print s
The fmap function is a generalized version of map. Just like map applies a function to the values inside a list, fmap can apply a function to values inside IO.
Another problem with this sample function is that if we call it again, it starts with a fresh seed instead of continuing the previous (pseudo)random sequence. Again, this make reproducing results impossible. In order to fix this problem, we need to pass in the seed and return a new seed. Unfortunately, randoms does not return the next seed for us, so we'll have to write this from scratch using random.
sample :: Int -> StdGen -> ([Int],StdGen)
sample n seed1 = case n of
0 -> ([],seed1)
k -> let (rs,seed2) = sample (k-1) seed1
(r, seed3) = random seed2
in ((r:rs),seed3)
Our main function is now
main :: IO ()
main = do
let seed1 = mkStdGen 123456
(xs,seed2) = sample 10 seed1
s = sum xs
(ys,seed3) = sample 10 seed2
t = sum ys
print s
print t
I know this seems like an awful lot of work just to to use random numbers, but the advantages are worth it. We can generate all of our randomness with a single seed which guarantees that the results can be reproduced.
Of course, this being Haskell, we can take advantage of Monads to get rid of all the manual threading of the seed values. This is a slightly more advanced method, but well worth learning since monads are ubiquitous in Haskell code.
We need these imports:
import System.Random
import Control.Monad
import Control.Applicative
Then we'll create a newtype which represents the action of turning a seed into a value and the next seed.
newtype Rand a = Rand { runRand :: StdGen -> (a,StdGen) }
We need Functor and Applicative instances or GHC will complain, but we can avoid implementing them for this example.
instance Functor Rand
instance Applicative Rand
And now for the Monad instance. This is where the magic happens. The >>= function (called bind) is the one place where we specify how to thread the seed value through the computation.
instance Monad Rand where
return x = Rand ( \seed -> (x,seed) )
ra >>= f = Rand ( \s1 -> let (a,s2) = runRand ra s1
in runRand (f a) s2 )
newRand :: Rand Int
newRand = Rand ( \seed -> random seed )
Now our sample function is extremely simple! We can take advantage of replicateM from Control.Monad which repeats a given action and accumulates the results in a list. All that funny business with the seed values is taken care of behind the scenes
sample :: Int -> Rand [Int]
sample n = replicateM n newRand
main :: IO ()
main = do
let seed1 = mkStdGen 124567
(xs,seed2) = runRand (sample 10) seed1
s = sum xs
print s
We can even stay inside the Rand monad if we need to generate random values multiple times.
main :: IO ()
main = do
let seed1 = mkStdGen 124567
(xs,seed2) = flip runRand seed1 $ do
x <- newRand
bs <- sample 5
cs <- sample 10
return $ x : (bs ++ cs)
s = sum xs
print s
I hope this helps!

Simple Haskell Monad - Random Number

I'm trying to extend the code in this post (accepted answer) to allow me to be able to call randomGen2 to get a random number, based on the function randomGen which takes a seed as an argument. But everytime I call randomGen2, despite returning an Int, I get an error about not been able to print Random (when infact I am only trying to print Int).
<interactive>:3:1:
No instance for (Show (Random Int))
arising from a use of `print'
Possible fix: add an instance declaration for (Show (Random Int))
In a stmt of an interactive GHCi command: print it
Here's the code:
import Control.Monad.State
type Seed = Int
randomGen :: Seed -> (Int, Seed)
randomGen seed = (seed,seed+1)
type Random a = State Seed a
randomGen2 :: Random Int
randomGen2 = do
seed <- get
let (x,seed') = randomGen seed
put seed'
return x
any ideas?
Update - expected behaviour
I'm hoping to be able to do something this from an interpreter (e.g. GHCI) -
> getRandomInit 1
> -- some other stuff, e.g. 2 + 3
> getRandom
i.e. I can set up my getRandom function with a seed, which then stores the seed using put, then this function returns and exits. I then do some other stuff, then call getRandom again, and the seed is retrieved from the Monad where it was stored.
randomGen2 returns a Random Int which is a State Seed Int so you'll need to use runState to get a result by providing a seed value e.g.
runState randomGen2 1
If you want to keep repeating the application of randomGen2 you can create a function like:
genRandoms :: Seed -> [Int]
genRandoms s = let (v, s') = runState randomGen2 s in v : genRandoms s'
or you could use sequence:
genRandoms :: Seed -> [Int]
genRandoms s = fst $ runState (sequence (repeat randomGen2)) s

Random Integer in Haskell [duplicate]

This question already has answers here:
Random number in Haskell [duplicate]
(5 answers)
Closed 8 years ago.
I am in the process of learning Haskell and to learn I want to generate a random Int type. I am confused because the following code works. Basically, I want an Int not an IO Int.
In ghci this works:
Prelude> import System.Random
Prelude System.Random> foo <- getStdRandom (randomR (1,1000000))
Prelude System.Random> fromIntegral foo :: Int
734077
Prelude System.Random> let bar = fromIntegral foo :: Int
Prelude System.Random> bar
734077
Prelude System.Random> :t bar
bar :: Int
So when I try to wrap this up with do it fails and I don't understand why.
randomInt = do
tmp <- getStdRandom (randomR (1,1000000))
fromIntegral tmp :: Int
The compiler produces the following:
Couldn't match expected type `IO b0' with actual type `Int'
In a stmt of a 'do' block: fromIntegral tmp :: Int
In the expression:
do { tmp <- getStdRandom (randomR (1, 1000000));
fromIntegral tmp :: Int }
In an equation for `randomInt':
randomInt
= do { tmp <- getStdRandom (randomR (1, 1000000));
fromIntegral tmp :: Int }
Failed, modules loaded: none.
I am new to Haskell, so if there is a better way to generate a random Int without do that would be preferred.
So my question is, why does my function not work and is there a better way to get a random Int.
The simple answer is that you can't generate random numbers without invoking some amount of IO. Whenever you get the standard generator, you have to interact with the host operating system and it makes a new seed. Because of this, there is non-determinism with any function that generates random numbers (the function returns different values for the same inputs). It would be like wanting to be able to get input from STDIN from the user without it being in the IO monad.
Instead, you have a few options. You can write all your code that depends on a randomly generated value as pure functions and only perform the IO to get the standard generator in main or some similar function, or you can use the MonadRandom package that gives you a pre-built monad for managing random values. Since most every pure function in System.Random takes a generator and returns a tuple containing the random value and a new generator, the Rand monad abstracts this pattern out so that you don't have to worry about it. You can end up writing code like
import Control.Monad.Random hiding (Random)
type Random a = Rand StdGen a
rollDie :: Int -> Random Int
rollDie n = getRandomR (1, n)
d6 :: Random Int
d6 = rollDie 6
d20 :: Random Int
d20 = rollDie 20
magicMissile :: Random (Maybe Int)
magicMissile = do
roll <- d20
if roll > 15
then do
damage1 <- d6
damage2 <- d6
return $ Just (damage1 + damage2)
else return Nothing
main :: IO ()
main = do
putStrLn "I'm going to cast Magic Missile!"
result <- evalRandIO magicMissile
case result of
Nothing -> putStrLn "Spell fizzled"
Just d -> putStrLn $ "You did " ++ show d ++ " damage!"
There's also an accompanying monad transformer, but I'd hold off on that until you have a good grasp on monads themselves. Compare this code to using System.Random:
rollDie :: Int -> StdGen -> (Int, StdGen)
rollDie n g = randomR (1, n) g
d6 :: StdGen -> (Int, StdGen)
d6 = rollDie 6
d20 :: StdGen -> (Int, StdGen)
d20 = rollDie 20
magicMissile :: StdGen -> (Maybe Int, StdGen)
magicMissile g =
let (roll, g1) = d20 g
(damage1, g2) = d6 g1
(damage2, g3) = d6 g2
in if roll > 15
then (Just $ damage1 + damage2, g3)
else Nothing
main :: IO ()
main = do
putStrLn "I'm going to case Magic Missile!"
g <- getStdGen
let (result, g1) = magicMissile g
case result of
Nothing -> putStrLn "Spell fizzled"
Just d -> putStrLn $ "You did " ++ show d ++ " damage!"
Here we have to manually have to manage the state of the generator and we don't get the handy do-notation that makes our order of execution more clear (laziness helps in the second case, but it makes it more confusing). Manually managing this state is boring, tedious, and error prone. The Rand monad makes everything much easier, more clear, and reduces the chance for bugs. This is usually the preferred way to do random number generation in Haskell.
It is worth mentioning that you can actually "unwrap" an IO a value to just an a value, but you should not use this unless you are 100% sure you know what you're doing. There is a function called unsafePerformIO, and as the name suggests it is not safe to use. It exists in Haskell mainly for when you are interfacing with the FFI, such as with a C DLL. Any foreign function is presumed to perform IO by default, but if you know with absolute certainty that the function you're calling has no side effects, then it's safe to use unsafePerformIO. Any other time is just a bad idea, it can lead to some really strange behaviors in your code that are virtually impossible to track down.
I think the above is slightly misleading. If you use the state monad then you can do something like this:
acceptOrRejects :: Int -> Int -> [Double]
acceptOrRejects seed nIters =
evalState (replicateM nIters (sample stdUniform))
(pureMT $ fromIntegral seed)
See here for an extended example of usage:Markov Chain Monte Carlo

Resources