Problems to make a function that rollsNDice in Haskell - haskell

I'm experimenting with randomness in Haskell and I wanted to do a function that given an Int n returns a list of states of random numbers between 1 and 6:
-- auxiliar function
rollDie :: State StdGen Int
rollDie = do generator <- get
let (value, newGenerator) = randomR (1,6) generator
put newGenerator
return value
rollNDice :: Int -> State StdGen [Int]
rollNDice n | n == 0 = [] :: State StdGen [Int]
| otherwise = (:) <$> rollDie <*> rollNDice (n-1)
but when I try to run it in ghci I get:
Couldn't match type ‘[a0]’
with ‘StateT StdGen Data.Functor.Identity.Identity [Int]’
Expected type: State StdGen [Int]
Actual type: [a0]
• In the expression: [] :: State StdGen [Int]
In an equation for ‘rollNDice’:
rollNDice n
| n == 0 = [] :: State StdGen [Int]
| otherwise = (:) <$> rollDie <*> rollNDice (n - 1)
I don't understand the error. Any ideas?

The reason this does not work is because [] has type [a], you can not use [] :: State StdGen [Int] to convert it to a State StdGen [Int].
You can however use pure :: Applicative m => a -> m a to wrap this in a State StdGen [Int]:
rollNDice :: Int -> State StdGen [Int]
rollNDice 0 = pure []
rollNDice n = (:) <$> rollDie <*> rollNDice (n-1)
That being said, you can make use of replicateM :: Applicative m => Int -> m a -> m [a] here to generate a list of n items:
import Control.Monad(replicateM)
rollNDice :: Int -> State StdGen [Int]
rollNDice = (`replicateM` rollDie)
For example:
Prelude System.Random Control.Monad.Trans.State Control.Monad> evalState (rollNDice 5) (mkStdGen 0)
[6,6,4,1,5]

Related

Why can't I call a function quicksort (randomList 10)?

I have the following code:
import Data.Array
import Control.Monad
import Data.Functor
import System.Random (randomRIO)
randomList 0 = return []
randomList n = do
r <- randomRIO (1,6)
rs <- randomList (n-1)
return (r:rs)
quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort [a | a <- xs, a <= x]
biggerSorted = quicksort [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSorted
randomList - creates a list of a given length and populates it with random values;
quicksort - quickly sorts the list.
I need to apply sorting to the created array:
quicksort (randomList 10), but an error occurs:
"Couldn't match expected type‘ [a] ’with actual type IO [Int]’"
You should include type signatures for all top-level names in your program. if you don't know them, load the file and ask GHCi: Main> :t randomList. Then copy-paste it to the file (or specialize it first, as you see fit). Place the type signature above the name it describes.
GHCi says
randomList ::
(System.Random.Random t, Num t, Num a, Eq a) => a -> IO [t]
but you most probably meant
randomList :: (System.Random.Random t, Num t) => Int -> IO [t]
randomList 0 = return []
randomList n = do
r <- randomRIO (1,6) -- randomRIO (1,6) :: IO t , r :: t
rs <- randomList (n-1) -- rs :: [t]
return (r:rs) -- r :: t , rs :: [t]
In general,
randomRIO (1,6) :: (System.Random.Random a, Num a) => IO a
You cast a 6-sided die n times and collect the results in a list. By the way the same thing is done by
sequence $ replicate n (randomRIO (1,6))
===
replicateM n (randomRIO (1,6))
> :t \n -> replicateM n (randomRIO (1,6))
:: (System.Random.Random a, Num a) => Int -> IO [a]
Then, GHCi also tells us that
quicksort :: Ord t => [t] -> [t]
But randomList n is IO [t], not [t]. To get to the [t] value living inside the IO [t], you need to do it on the inside:
sortRandom :: (Ord t, Monad m) => m [t] -> m [t]
sortRandom randomlist = do
xs <- randomlist -- randomlist :: IO [t] , xs :: [t]
let ys = quicksort xs
return ys
The above can be abbreviated to
sortRandom :: (Ord t, Monad m) => m [t] -> m [t]
sortRandom = liftM quicksort -- for monads
or
sortRandom :: (Ord t, Functor f) => f [t] -> f [t]
sortRandom = fmap quicksort -- for functors
whichever you prefer. Both work with IO which is a monad, and any monad is also a functor. So in the end you can define
foo :: Int -> IO [Int]
foo n = liftM quicksort $ replicateM n (randomRIO (1,6))

Getting Access to 'a' in StateT

I'm trying to write a function with StateT only to learn more about it.
In f, I'd like to access to the Int in the last type argument of StateT [Int] IO Int:
f :: StateT [Int] IO Int
f = state $ \xs -> update (error "I want a") xs
update :: Int -> [Int] -> (Int, [Int])
update x [] = (x, [])
update x (y:ys) = (x+y, ys)
Here's how I'd like to call it:
let x = return 55 :: StateT [Int] IO Int
Referencing runStateT:
*Main> :t runStateT
runStateT :: StateT s m a -> s -> m (a, s)
I'd expect to run it:
runStateT (f x) [1,2,3]
to get the following from GHCI, i.e. the IO (Int, [Int]) gets printed:
(56, [2,3])
since the inner a, i.e. 55, + 1, i.e. from [1,2,3], returns (56, [2,3]).
How can I write the above function, getting access to the a?
Ok, here's what say you want:
>>> let x = return 55 :: StateT [Int] IO Int
>>> runStateT (f x) [1,2,3]
(56, [2,3])
So let's work backwards from that.
From the use of f, we can infer its type -
f :: StateT [Int] IO Int -> StateT [Int] IO Int
Note the difference from your given type for f in the question - namely f is a function between values of type StateT [Int] IO Int, not a value of that type.
To define f, we need (>>=) :: Monad m => m a -> (a -> m b) -> m b. This will allow us to take our input of type StateT [Int] IO Int and run some computation on the Int the input computes.
f x = x >>= \i -> state (splitAt 1) >>= \[j] -> return (i + j)
or, using do-notation:
f x = do
i <- x
[j] <- state (splitAt 1)
return (i + j)
Which gives us exactly the result we want.
While this works, it's highly non-idiomatic. Rather than passing monadic values in as inputs to functions and binding them inside the function, it's far more common to define functions that take regular values and return monadic ones, using the bind operator (>>=) outside.
So it'd be far more normal to define
shiftAdd :: Int -> StateT [Int] IO Int
shiftAdd i = do
[j] <- state (splitAt 1)
return (i + j)
So now we can run not only
>>> runStateT (shiftAdd 55) [1,2,3]
(56,[2,3])
but also
>>> runStateT (shiftAdd 55 >>= shiftAdd >>= shiftAdd)
(61,[])
It's still not as idiomatic as it could be as:
I made it unnecessarily partial by using splitAt (it'll throw an exception if the state list is empty)
it's unnecessarily specific (doesn't use IO at all, but we can't use it with other base monads)
Fixing that up gives us:
shiftAdd' :: (Monad m, Num a) => a -> StateT [a] m a
shiftAdd' i = state $ \js -> case js of
[] -> (i, [])
j : js -> (i + j, js)
Which works just fine:
>>> runStateT (return 55 >>= shiftAdd') [1,2,3]
(56,[2,3])
>>> runStateT (return 55 >>= shiftAdd' >>= shiftAdd' >>= shiftAdd') [1,2,3]
(61,[])
>>> runStateT (return 55 >>= shiftAdd' >>= shiftAdd' >>= shiftAdd') []
(55,[])

How can I get 8-x random values in Haskell?

I'm trying to make a function worp that returns 2 lists of integers.
Where the first list of integers is the result of 8 minus the length of the input list, dice throws.
And the second list is the input list.
This is my code:
import System.Random
worp :: [Int] -> [[IO Int]]
worp d = [werpDobbelstenen (8-length d),d]
werpDobbelstenen :: Int -> [IO Int]
werpDobbelstenen 0 = []
werpDobbelstenen x = randomRIO (1,6):werpDobbelstenen x-1
Im getting this error:
System.IO> :load "X:\\haskell\\dobbel.hs"
ERROR file:.\dobbel.hs:17 - Instance of Num [IO Int] required for definitio of werpDobbelstenen
First, I would return an IO [Int] value for simplicity:
import Control.Monad -- replicateM
import System.Random -- randomRIO
werpDobbelstenen :: Int -> IO [Int]
werpDobbelstenen n = replicateM n (randomRIO (1,6))
Now, define your worp more simply, as one that simply takes a list of Int and returns the desired pair of lists.
worp' :: [Int] -> ([Int], [Int])
worp' d = (d, map (\x -> x - length d) d)
And finally, you can simply map worp over the result of werpDobbelstenen to get an IO ([Int], [Int]) value.
worp :: Int -> IO ([Int], [Int])
worp n = fmap worp' (werpDobbelstenen n)
After a little more thinking, I think this is what you want:
import Control.Monad -- replicateM
import System.Random -- randomRIO
werpDobbelstenen :: Int -> IO [Int]
werpDobbelstenen n = replicateM n (randomRIO (1,6))
worp' :: [Int] -> IO ([Int], [Int])
worp' d = let n = 8 - length d
in do d' <- werpDobbelstenen n
return (d, d')
worp :: Int -> IO ([Int], [Int])
worp n = werpDobbelstenen n >>= worp'
>>> worp 6
([4,1,2,5,6,4],[1,2])
In this case, the second value of the tuple is always an empty list for n >= 8. You may want to do something different for values larger than 8.

Haskell: Random number

I have written a function to get a pair from [-10,10] by random.
import System.Random
main =
do {
s <- randomNumber
; b <- randomNumber
; print (head s,head b)}
randomNumber :: IO [Int]
randomNumber = sequence $ replicate 1 $ randomRIO (-10,10)
Now I want to take a list like [(1,2),(2,3),(2,3)], all the number is come from the randomNumber. How can I do that? I don't know how to achieve that.
I have tried to use state to get random, but somehow I can't use state on my computer.
I did this :
import System.Random
import Control.Monad.State
randomSt :: (RandomGen g, Random a) => State g a
randomSt = State random
But when I compiled it, it showed: Not in scope: data constructor ‘State’
So if all you want is a function
randomPairs :: IO [(Int, Int)]
then we can do something like
randomList :: IO [Int]
randomList = randomRs (-10, 10) `fmap` newStdGen
randomPairs = ??? randomList randomList
where ??? takes two IO [Int] and "zips" them together to form a IO [(Int, Int)]. We now turn to hoogle and query for a function [a] -> [a] -> [(a, a]) and we find a function zip :: [a] -> [b] -> [(a, b)] we now just need to "lift" zip into the IO monad to work with it across IO lists so we end up with
randomPairs = liftM2 zip randomList randomList
or if we want to be really fancy, we could use applicatives instead and end up with
import Control.Applicative
randomPairs = zip <$> randomList <*> randomList
But judging from your randomNumber funciton, you really just want one pair. The idea is quite similar. Instead of generating a list, we generate just one random number with randomRIO (-10, 10) and lift (,) :: a -> b -> (a, b) resulting in
randomPair = (,) <$> randomRIO (-10, 10) <*> randomRIO (-10, 10)
Finally, the State data constructor went away a while ago because the MTL moved from having separate State and StateT types to making State a type synonym. Nowadays you need to use the lowercase state :: (s -> (s, a)) -> State s a
To clarify, my final code is
import System.Random
import Control.Monad
randomList :: IO [Int]
randomList = randomRs (-10, 10) `fmap` newStdGen
pairs :: IO [(Int, Int)]
pairs = liftM2 zip randomList randomList
somePairs n = take n `fmap` pairs
main = somePairs 10 >>= print

Improving code to generate a distribution

I am new to Haskell and I wonder how/if I can make this code more efficient and tidy. It seems unnecessarily long and untidy.
My script generates a list of 10 averages of 10 coin flips.
import Data.List
import System.Random
type Rand a = StdGen -> Maybe (a,StdGen)
output = do
gen <- newStdGen
return $ distBernoulli 10 10 gen
distBernoulli :: Int -> Int -> StdGen -> [Double]
distBernoulli m n gen = [fromIntegral (sum x) / fromIntegral (length x) | x <- lst]
where lst = splitList (randomList (n*m) gen) n
splitList :: [Int] -> Int -> [[Int]]
splitList [] n = []
splitList lst n = take n lst : splitList (drop n lst) n
randomList :: Int -> StdGen -> [Int]
randomList n = take n . unfoldr trialBernoulli
trialBernoulli :: Rand Int
trialBernoulli gen = Just ((2*x)-1,y)
where (x,y) = randomR (0,1) gen
Any help would be appreciated, thanks.
I'd tackle this problem in a slightly different way. First I'd define a function that would give me an infinite sampling of flips from a Bernoulli distribution with success probability p:
flips :: Double -> StdGen -> [Bool]
flips p = map (< p) . randoms
Then I'd write distBernoulli as follows:
distBernoulli :: Int -> Int -> StdGen -> [Double]
distBernoulli m n = take m . map avg . splitEvery n . map val . flips 0.5
where
val True = 1
val False = -1
avg = (/ fromIntegral n) . sum
I think this matches your definition of distBernoulli:
*Main> distBernoulli 10 10 $ mkStdGen 0
[-0.2,0.4,0.4,0.0,0.0,0.2,0.0,0.6,0.2,0.0]
(Note that I'm using splitEvery from the handy split package, so you'd have to install the package and add import Data.List.Split (splitEvery) to your imports.)
This approach is slightly more general, and I think a little neater, but really the main difference is just that I'm using randoms and splitEvery.
EDIT: I posted this too fast and didn't match behavior, it should be good now.
import Control.Monad.Random
import Control.Monad (liftM, replicateM)
KNOWLEDGE: If you like randoms then use MonadRandom - it rocks.
STYLE: Only importing symbols you use helps readability and sometimes maintainability.
output :: IO [Double]
output = liftM (map dist) getLists
Note: I've given output an explicit type, but know it doesn't have to be IO.
STYLE:
1) Its usually good to separate your IO from pure functions. Here I've divided out the getting of random lists from the calculation of distributions. In your case it was pure but you combined getting "random" lists via a generator with the distribution function; I would divide those parts up.
2) Read Do notation considered harmful. Consider using >>= instead of
output = do
gen <- new
return $ dist gen
you can do:
output = new >>= dist
Wow!
dist :: [Int] -> Double
dist lst = (fromIntegral (sum lst) / fromIntegral (length lst))
getLists :: MonadRandom m => Int -> Int -> m [[Int]]
getLists m n= replicateM m (getList n)
KNOWLEDGE In Control.Monad anything ending in an M is like the original but for monads. In this case, replicateM should be familiar if you used the Data.List replicate function.
getList :: MonadRandom m => Int -> m [Int]
getList m = liftM (map (subtract 1 . (*2)) . take m) (getRandomRs (0,1::Int))
STYLE: If I do something lots of times I like to have a single instance in its own function (getList) then the repetition in a separate function.
I'm not sure I understand your code or your question...
But it seems to me all you'd need to do is generate a list of random ones and zeroes, and then divide each of them by their length with a map and add them together with a foldl.
Something like:
makeList n lis = if n /= 0 then
makeList (n-1) randomR(0,1) : lis
else
lis
And then make it apply a Map and Foldl or Foldr to it.
Using the above, I am now using this.
import Data.List
import System.Random
type Rand a = [a]
distBernoulli :: Int -> Int -> StdGen -> [Double]
distBernoulli m n gen = [fromIntegral (sum x) / fromIntegral (length x) | x <- lst]
where lst = take m $ splitList (listBernoulli gen) n
listBernoulli :: StdGen -> Rand Int
listBernoulli = map (\x -> (x*2)-1) . randomRs (0,1)
splitList :: [Int] -> Int -> [[Int]]
splitList lst n = take n lst : splitList (drop n lst) n
Thanks for your help, and I welcome any further comments :)

Resources