Improving code to generate a distribution - haskell

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 :)

Related

How do I deal with the error "No instance for (Control.Monad.IO.Class.MonadIO [])"?

Good evening everybody! This is a question concerning Haskell. I want to get x random elements from a list by using a function.
The problem I get is that when I try to use random numbers, with randomRIO. I get the error message:
No instance for (Control.Monad.IO.Class.MonadIO [])
arising from a use of `randomRIO'
This error message suddenly goes away when i use print or return. But I dont want to use print, and return messes up the output to a nested list [[a]] instead of [a].
Does any of you have a tip on what I can do to extract x random elements from the list, in the form of a list?
The type would be something like this. xRanElems :: [a] -> Int -> [a]
where the second Int is an accumulator but I got that covered.
xRanElems xs n = do
r <- randomRIO (0, n)
xRanElems2 xs n r
where n is just length xs - 1
xRanElems2 xs n r = (xs !! r) : (xRanElems (xsWithOutSelectedElem xs r) (n-1))
Thankful for any input!
The following typechecks:
import System.Random
xRanElems :: [a] -> Int -> IO [a]
xRanElems xs n = do
-- randomRIO :: Random t
-- => (t, t) -> IO t
r <- randomRIO (0, n) -- r :: Int
xRanElems2 xs n r
xRanElems2 :: [a] -> Int -> Int -> IO [a]
xRanElems2 xs n r =
let (a,b:c) = splitAt r xs
in
fmap (b :) -- [a] -> [a]
(xRanElems -- IO [a] -> IO [a]
(a++c) (n-1))
Trying to run it, e.g. with xRanElems [1..3] 2, reveals that it loops forever.
This is because you need to provide the base case in xRanElems to stop the recursion, e.g. returning [] when n <= 0.
The above code also contains an off-by-1 error which you're invited to fix.

Mutually recursive IO definitions

I can write the following:
f :: [Int] -> [Int]
f x = 0:(map (+1) x)
g :: [Int] -> [Int]
g x = map (*2) x
a = f b
b = g a
main = print $ take 5 a
And things work perfectly fine (ideone).
However, lets say I want g to do something more complex than multiply by 2, like ask the user for a number and add that, like so:
g2 :: [Int] -> IO [Int]
g2 = mapM (\x -> getLine >>= (return . (+x) . read))
How do I then, well, tie the knot?
Clarification:
Basically I want the list of Ints from f to be the input of g2 and the list of Ints from g2 to be the input of f.
The effectful generalization of lists is ListT:
import Control.Monad
import Pipes
f :: ListT IO Int -> ListT IO Int
f x = return 0 `mplus` fmap (+ 1) x
g2 :: ListT IO Int -> ListT IO Int
g2 x = do
n <- x
n' <- lift (fmap read getLine)
return (n' + n)
a = f b
b = g2 a
main = runListT $ do
n <- a
lift (print n)
mzero
You can also implement take like functionality with a little extra code:
import qualified Pipes.Prelude as Pipes
take' :: Monad m => Int -> ListT m a -> ListT m a
take' n l = Select (enumerate l >-> Pipes.take n)
main = runListT $ do
n <- take' 5 a
lift (print n)
mzero
Example session:
>>> main
0
1<Enter>
2
2<Enter>
3<Enter>
7
4<Enter>
5<Enter>
6<Enter>
18
7<Enter>
8<Enter>
9<Enter>
10<Enter>
38
You can learn more about ListT by reading the pipes tutorial, specifically the section on ListT.

Combining State and List Monads

Consider the following Haskell code:
import Control.Monad.State
test :: Int -> [(Int, Int)]
test = runStateT $ do
a <- lift [1..10]
modify (+a)
return a
main = print . test $ 10
This produces the following output:
[(1,11),(2,12),(3,13),(4,14),(5,15),(6,16),(7,17),(8,18),(9,19),(10,20)]
However I would like to produce the following output instead:
[(1,11),(2,13),(3,16),(4,20),(5,25),(6,31),(7,38),(8,46),(9,55),(10,65)]
This is easy to do in an impure language like JavaScript:
function test(state) {
var result = [];
for (var a = 1; a <= 10; a++) {
result.push([a, state += a]);
}
return result;
}
How do you do the same thing in Haskell?
The Haskell types and the logic of your JavaScript code doesn't match: the JS code has two values in the state (the Int, and the returned list). In contrast, StateT Int [] a doesn't really have a list in the state; rather, it runs stateful actions multiple times (with the initial state unchanged for each run) and collects all the results in a list.
In other words, the JS code has type State (Int, [(Int, Int)]) [(Int, Int)]. But this is too literal a translation and we can write more elegant Haskell code.
Sticking to the State monad, we can return a list with mapM or forM:
test2 :: Int -> [(Int, Int)]
test2 = evalState $
forM [1..10] $ \a -> do
s <- get <* modify (+a)
return (a, s)
Some lens magic can make it more similar to the JS code:
{-# LANGUAGE TupleSections #-}
import Control.Lens
test3 :: Int -> [(Int, Int)]
test3 = evalState $
forM [1..10] $ \a -> (a,) <$> (id <+= a)
However, we can do away with State altogether, and it's the best approach here, I think:
import Control.Monad (ap)
test4 :: Int -> [(Int, Int)]
test4 n = ap zip (tail . scanl (+) n) [1..10]
-- or without ap : zip [1..10] (drop 1 $ scanl (+) n [1..10])
Your series is quadratic and can be generated more simply:
series = fmap (\x -> (x, quot (x*x + x) 2 + 10)) [1..]
If you want a recurrence relation you might write it as this:
series :: [(Int,Int)]
series = let
series' x y = (x, x + y) : series' (x + 1) (x + y)
in series' 1 10
There is no compelling reason that I see to use monads.

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

Haskell recursion with random numbers and IO

For the 99 Haskell questions, specifically the 23rd one, I need to
"Extract a given number of randomly selected elements from a list.
Example (in lisp):
(rnd-select '(a b c d e f g h) 3)
(E D A)
"
Which I have implemented like so:
import System.Random
import Control.Monad
removeAt :: [a] -> Int -> [a]
removeAt (x:xs) i
| i > 0 = x : removeAt xs (i-1)
| otherwise = xs
rndSelect :: (RandomGen g) => [a] -> Int -> g -> IO [a]
rndSelect _ 0 _ = return []
rndSelect xs n gen = do
let (pos, newGen) = randomR (0, length xs - 1) gen
rest <- rndSelect (removeAt xs pos) (n-1) newGen
return $ (xs!!pos):rest
-- for an explanation of what this is doing see EXPLANATION below
As far as I can tell this works, but what I'm concerned about are those last two lines. I'm new to this and I don't know the associated costs of the '<-' operator is or bouncing in and out of IO repeatedly like I'm doing. Is this efficient, is there a better way to do this that doesn't involve bouncing IO, or is there no real overheads involved?
Any insight you have is appreciated, since I've only recently started learning these more sophisticated concepts in Haskell and haven't yet gotten used to reasoning about Haskell's IO system.
EXPLANATION: In order to do this I've decided that I should randomly select one element from the list using the randomR function (returns a random number in a given range), and keep doing this recursively until I've taken n elements.
I've made a couple assumptions about the problem that have lead me to this approach. Firstly I've assumed that rndSelect can select a specific element from the list only once, and secondly I've assumed that each element should have an equal probability of being picked.
PS: it's my first question on SO so if I've formatted the question poorly feel free to tell me.
You do not need IO for this, since randomR does not require it. What you need to do however, is to thread the random number generator through your computation:
import System.Random
import Control.Monad
removeAt :: [a] -> Int -> [a]
removeAt (x:xs) i
| i > 0 = x : removeAt xs (i-1)
| otherwise = xs
rndSelect :: (RandomGen t, Num a) => [a1] -> a -> t -> ([a1], t)
rndSelect _ 0 g = ([],g)
rndSelect xs n gen =
let (pos, newGen) = randomR (0, length xs - 1) gen
(rest,ng) = rndSelect (removeAt xs pos) (n-1) newGen
in ((xs!!pos):rest, ng)
If you're concerned about overheads going from IO to pure code, don't be. Instead you can try mwc-random package which will be atleast an order of magnitude faster in this case. Further, you could get additional benefit using any random access data structure instead of list if you have many elements.
You can avoid IO as :
rndSelect :: (RandomGen g) => [a] -> Int -> g -> [a]
rndSelect _ 0 _ = return []
rndSelect xs n gen = do
let (pos, newGen) = randomR (0, length xs - 1) gen
rest = rndSelect (removeAt xs pos) (n-1) newGen
in (xs!!pos):rest

Resources