How to convert a STArray to a List in Haskell? - haskell

Is there a function can do what the function arrayToList do:
import Data.Array.ST
import Control.Monad.ST
genArray :: ST s [Int]
genArray = do
a <- new Array (0, 99) 0 :: ST s (STArray s Int Int)
writeArray a 0 1
{- ... write something to the array ... -}
return arrayToList(a)
If not, how to write one?

You don't need IO for this, constructing a list is a pure operation:
genArray :: [Int]
genArray = runST $ do
a <- newArray (0, 99) 0 :: ST s (STArray s Int Int)
writeArray a 0 1
{- ... write something to the array ... -}
getElems a

Use stToIO and getElems:
genArray :: IO [Int]
genArray = stToIO $ do
a <- newArray (0,99) 0 :: ST s (STArray s Int Int)
writeArray a 0 1
getElems a

Related

Problems to make a function that rollsNDice in 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]

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.

Difference in GHC versions - compile error

I was practicing my Haskell and I came across a weird problem which I was unable to find a solution to on the Internet. I decided to solve this problem:
https://www.hackerrank.com/challenges/fibonacci-fp
In as many ways I can think of. One way is to perform recursion with memoization where I want to use State monad as a cache. I have GHC 7.10.2 on my Windows 10 and GHC 7.6.2 on my Ubuntu 14.04. This code below compiles (and runs very well) on 7.6.2 and doesn't compile on 7.10.2 giving error wherever I type 'Map', for example:
Not in scope: type constructor or class: 'Map.Map'
Not in scope: 'Map.lookup'
module Main (
main
) where
import qualified Data.Map as Map
import Control.Monad.State
type CacheState = Map.Map Int Int
type IOState a = StateT CacheState IO a
modNum :: Int
modNum = 100000007
fibsMod :: [Int]
fibsMod = 0 : 1 : zipWith (\x y -> (x + y) mod modNum ) fibsMod (tail fibsMod)
-- | calculate Fibs with memoization in map
memoizedFib :: Int -> IOState Int
memoizedFib n = do
state <- get
let x = Map.lookup n state
case x of
Just y ->
return y
Nothing -> do
n1 <- memoizedFib (n - 1)
n2 <- memoizedFib (n - 2)
let n3 = mod (n1 + n2) modNum
put (Map.insert n n3 state)
return n3
query :: [Int] -> IOState ()
query [] = return ()
query (n:ns) = do
fibNum <- memoizedFib n
liftIO $ print fibNum
query ns
main :: IO ()
main = do
inputdata <- getContents
let intList = (map (read :: String -> Int) . tail . words) inputdata
evalIOState $ query intList
where
initState :: Int -> Map.Map Int Int
initState upTo = Map.fromList $ zip [0 .. upTo] $ take upTo fibsMod
--initState upTo = Map.fromList $ [(0, 0), (1, 1)]
evalIOState :: IOState a -> IO a
evalIOState m = evalStateT m (initState 10001)
Does anybody know why am I facing this problem? It's very disturbing.
Additional question
As you can see I didn't perform exactly recursion with memoization. However leaving one of those lines uncommented can change approach:
initState upTo = Map.fromList $ zip [0 .. upTo] $ take upTo fibsMod
--initState upTo = Map.fromList $ [(0, 0), (1, 1)]
The problem is that using the second line performs terrible. I don't know where I made a mistake, but I think it should run in linear time with memoization. However with this line my algorithm is clearly exponential (I couldn't even get the answer for 50-th Fib number - that long). What did I do wrong in this case?
UPDATE
Thanks to your comments I fixed my code. Obviously there was a problem with mod function (I completely don't know how did this compile on GHC 7.6.2). Also I changed:
import qualified Data.Map as Map
to:
import qualified Data.Map.Strict as Map
and now this code below works as intended:
module Main (
main
) where
import qualified Data.Map.Strict as Map
import Control.Monad.State
type CacheState = Map.Map Int Int
type IOState a = StateT CacheState IO a
modNum :: Int
modNum = 100000007
fibsMod :: [Int]
fibsMod = 0 : 1 : zipWith (\x y -> (x + y) `mod` modNum) fibsMod (tail fibsMod)
-- | calculate Fibs with memoization in map
memoizedFib :: Int -> IOState Int
memoizedFib n = do
state <- get
let x = Map.lookup n state
case x of
Just y ->
return y
Nothing -> do
n1 <- memoizedFib (n - 1)
n2 <- memoizedFib (n - 2)
state <- get
let n3 = mod (n1 + n2) modNum
put (Map.insert n n3 state)
return n3
query :: [Int] -> IOState ()
query [] = return ()
query (n:ns) = do
fibNum <- memoizedFib n
liftIO $ print fibNum
query ns
main :: IO ()
main = do
inputdata <- getContents
let intList = (map (read :: String -> Int) . tail . words) inputdata
evalIOState $ query intList
where
initState :: Int -> Map.Map Int Int
--initState upTo = Map.fromList $ zip [0 .. upTo] $ take upTo fibsMod
initState upTo = Map.fromList [(0, 0), (1, 1)]
evalIOState :: IOState a -> IO a
evalIOState m = evalStateT m (initState 10001)
So now the question comes down to: Why did I need to use Data.Map.Strict, how is it different and why GHC 7.6.2 didn't need it?

getLine x times haskell

Based on Hackerrank question
My problem is how can I do getLine t times on stdIn?
main = do
t <- getInt
let x = [divisorsInNumber unsafeGetInt | a <-[1..t] ]
print x
getInt :: IO Int
getInt = fmap read getLine
unsafeGetInt :: Int
unsafeGetInt = unsafePerformIO getInt
divisorsInNumber n = length $ filter (== True) $ map (isDivisor n) (integralToListOfInts n)
Just replicate t times the getLine operation with replicateM:
import Control.Monad (replicateM)
getLines :: Int -> IO [String]
getLines t = replicateM t getLine
Thus getInts, that is getInt t times, can be expressed with:
getInts :: Int -> IO [Int]
getInts = fmap read <$> getLines
The full code rewritten to use getInts could be:
import Control.Applicative ((<$>))
import Control.Monad (replicateM)
getLines :: Int -> IO [String]
getLines n = replicateM n getLine
getInts :: Int -> IO [Int]
getInts n = fmap read <$> getLines n
getInt :: IO Int
getInt = fmap read getLine
divisorsInNumber :: Int -> Int
divisorsInNumber n = length $ filter (isDivisor n) (integralToListOfInts n)
main :: IO ()
main = do
t <- getInt
nums <- getInts t
let x = [divisorsInNumber num | num <- nums]
print x

haskell Convert IO Int to Int System.Random.MWC

I would like to convert an IO Int to Int from System.Random.MWC, using unsafePerformIO. It does work in ghci:
Prelude System.Random.MWC System.IO.Unsafe> let p = unsafePerformIO(uniformR (0, 30) gen :: IO Int)
Prelude System.Random.MWC System.IO.Unsafe> p
11
Prelude System.Random.MWC System.IO.Unsafe> :t p
p :: Int
However in GHC
import System.Random.MWC
import System.IO.Unsafe
main :: IO()
main = do
gen <-createSystemRandom
print $! s 30 gen
s :: Int-> GenIO -> Int
s !k g = unsafePerformIO(uniformR (0, k - 1) g)
it returns
ghc: panic! (the 'impossible' happened)
(GHC version 7.6.3 for i386-unknown-linux):
make_exp (App _ (Coercion _))
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
There's really no need for unsafePerformIO here. Just change the type of s to return IO Int and use do-notation or the bind operator to feed the result to print.
s :: Int -> GenIO -> IO Int
s k g = uniformR (0, k - 1) g
main :: IO ()
main = do
gen <- createSystemRandom
x <- s 30 gen
print x
or
main = do
gen <- createSystemRandom
print =<< s 30 gen
or
main = print =<< s 30 =<< createSystemRandom

Resources