For the sake of understanding I played around with IORef and tried to come up with something that would be close to having a global, mutable state:
import Data.IORef
x :: IO (IORef Int)
x = newIORef 0
incrAndPrint :: IO ()
incrAndPrint = do z <- x
modifyIORef z (+1)
readIORef z >>= putStrLn . show
main :: IO ()
main = incrAndPrint >> incrAndPrint
However, to my surprise this prints
1
1
not
1
2
Could someone explain why?
Moreover, is there a way to make this 'work'? If not, why?
Your x is an IO action that creates a new IORef Int so when you use it it will always create a new one starting at 0.
You can easily make this work by increment the same reference both times:
incrAndPrint :: IORef Int -> IO ()
incrAndPrint z = do
modifyIORef z (+1)
readIORef z >>= print
main = do
z <- x
incrAndPrint z
incrAndPrint z
If you really, really have to use a global mutable state you can do it with
unsafePerformIO, which works with GHC because it will make sure the IORef isn't
accessed before it's initialized and the NOINLINE prevents a new reference to be
created wherever you use it.
import Data.IORef
import System.IO.Unsafe
x :: IORef Int
x = unsafePerformIO $ newIORef 0
{-# NOINLINE x #-}
incrAndPrint :: IO ()
incrAndPrint = do
modifyIORef x (+1)
readIORef x >>= putStrLn . show
main :: IO ()
main = incrAndPrint >> incrAndPrint
Related
I would like to use IO Int to represent a stream of integers by hiding an IORef in its definition:
tickrate :: Int
tickrate = 20000
ioIntTest :: Int -> IO Int
ioIntTest i0 = do
intRef <- newIORef i0
f intRef
where
f :: IORef Int -> IO Int
f ref = do
i <- readIORef ref
modifyIORef ref (+1)
return i
ioTest :: Int -> IO ()
ioTest n = do
let intStream = ioIntTest n
intStreamToPrint intStream
where
intStreamToPrint is = do
threadDelay tickrate
c <- is
putStrLn (show c)
intStreamToPrint is
However, if I call ioTest n, rather than seeing an increasing list of numbers printed to the screen, I see only the starting number, n, repeating indefinitely.
While I could refactor this code so that incrementing and reading the value of ioIntTest i0 are done separately, I would like to know if/why the following is impossible:
Can I make an IO Int such that each time it is used in (>>=) (either explicitly or implicitly in do notation) the returned Int mutates?
While such an IO Int is perhaps not referentially transparent, I thought that was the point of wrapping computations in the IO monad.
Such a refactoring could be:
tickrate :: Int
tickrate = 20000
ioIntMutate :: IORef Int -> IO Int
ioIntMutate ref = do
i <- readIORef ref
modifyIORef ref (+1)
return i
ioTest :: Int -> IO ()
ioTest n = do
intStream <- newIORef n
intStreamToPrint intStream
where
intStreamToPrint is = do
threadDelay tickrate
c <- ioIntMutate is
putStrLn (show c)
intStreamToPrint is
In other words, is there any way to replace the line ioIntMutate is in the third-to-last line with an IO Int?
You can use IO (IO Int) for that. Like this:
ioIntTest :: Int -> IO (IO Int)
ioIntTest n = do
ref <- newIORef n
pure $ do
i <- readIORef ref
writeIORef ref (i+1)
pure i
ioTest :: Int -> IO ()
ioTest n = do
intStream <- ioIntTest n
intStreamToPrint intStream
where
intStreamToPrint is = do
threadDelay tickrate
c <- is
putStrLn (show c)
intStreamToPrint is
Note that the only difference between my ioTest and your ioTest is this line:
let intStream = ioIntTest n -- yours
intStream <- ioIntTest n -- mine
And, by the way, this solution is not so contrived. I have used a trick like this before to hide internal implementation details of an async RPC channel; or for another example on Hackage, check out once. You don't need to know whether that's implemented with IORefs or some other trick, and the author can switch tricks as they find better ones.
As a stylistic note, I'd write ioTest a little differently. One of these two:
ioTest :: Int -> IO ()
ioTest n = do
intStream <- ioIntTest n
forever (intStream >>= print >> threadDelay tickrate)
-- OR
forever $ do
intStream >>= print
threadDelay tickrate
Given:
λ: >let m = newMVar "foo"
λ: >m >>= readMVar
"foo"
I tried to use modifyMVar_:
λ: >:t modifyMVar_
modifyMVar_ :: MVar a -> (a -> IO a) -> IO ()
through:
λ: >m >>= \mvar -> modifyMVar_ mvar (\_ -> return "bar")
But, it doesn't look like it modified m from "foo" to "bar".
λ: >m >>= readMVar
"foo"
What'd I do wrong?
m creates new MVar with "foo" every time it's called. You're modifying one MVar then making a new one and checking that. It is the same problem as seen here Setting off a interval on application launch in a Haskell Servant app with exception that there it was an IORef.
myVar <- m
modifyMVar_ myVar (\_ -> return "bar")
readMVar myVar
This should give you "bar" as expected.
I have the following code:
while :: IO Bool -> IO () -> IO ()
while test body =
do b <- test
if b
then do {body ; while test body} -- same-line syntax for do
else return ()
I need to implement the factorial function using imperative-style programming. what I have to do is to create and initialize variables using newIORef, modify their values using a while loop with readIORef and writeIORef, then have the IO action return a pair consisting of the input n and the final result.
This is what I have done so far:
fact :: Integer -> IO (Integer, Integer)
fact n = do r <- newIORef n --initialize variable
while
(do {v <- readIORef n; n})
(do {v <- readIORef r; writeIORef (...)) --modify the value (?)
readIORef r
This is my attempt to write the factorial function. This is obviously does not work. Any help would be appreciated.
I think maybe it's time to give you some working version:
fact :: Integer -> IO (Integer, Integer)
fact n = do
i <- newIORef 1
acc <- newIORef 1
while (lessOrEqualN i) (step i acc)
acc' <- readIORef acc
return $ (n, acc')
where
lessOrEqualN iRef = do
i' <- readIORef iRef
return $ i' <= n
step iRef accRef = do
i' <- readIORef iRef
acc' <- readIORef accRef
writeIORef accRef (acc' * i')
writeIORef iRef (i'+1)
as you can see I used an loop reference i and an accumulator reference acc always reading, writing the changing values.
To make this (hopefully) a bit more readable I extracted the test and the body of the while into lessOrEqualN and step.
Of course there are easier ways to do this (modifyIORef) but I guess you have to use those.
PS: you play with it a bit - maybe you want to handle negative values differently or whatever
this might be a bit cleaner (putting both mutables into the same ref):
fact :: Integer -> IO (Integer, Integer)
fact n = do
ref <- newIORef (1,1)
while (lessOrEqualN ref) (step ref)
(_,acc) <- readIORef ref
return $ (n, acc)
where
lessOrEqualN ref = do
(i,_) <- readIORef ref
return $ i <= n
step ref = do
(i,acc) <- readIORef ref
writeIORef ref (i+1, acc * i)
I think Carsten's answer can be made a bit cleaner like this:
{-# LANGUAGE TupleSections #-}
import Control.Monad
import Data.IORef
fact :: Integer -> IO (Integer, Integer)
fact n = do
counter <- newIORef 1
result <- newIORef 1
while (fmap (<=n) (readIORef counter)) $ do
i <- postIncrement counter
modifyIORef result (*i)
fmap (n,) (readIORef result)
while :: IO Bool -> IO () -> IO ()
while test body =
do b <- test
if b
then do {body ; while test body} -- same-line syntax for do
else return ()
postIncrement :: Enum a => IORef a -> IO a
postIncrement ref = do
result <- readIORef ref
modifyIORef ref succ
return result
What I'm doing here is:
Using modifyIORef to cut down on the number of paired readIORef/writeIORef calls.
Using fmap to reduce the need for auxiliary functions to test the contents of an IORef.
Write a generic, reusable postIncrement function and use that to shorten fact further.
But frankly, I think your instructor's insistence that you use this while function is a bit silly. It doesn't make for clean code. If I was told to write an imperative factorial with IORef I'd first write this, just using the forM_ loop from the library:
factorial :: Integer -> IO (Integer, Integer)
factorial n = do
result <- newIORef 1
forM_ [2..n] $ \i -> do
modifyIORef result (*i)
fmap (n,) (readIORef result)
And that's because I was too dumb to remember replicateM_ :: Monad m => Int -> m a -> m () right away...
In the following program Fibonacci number is generated from a given integer (generated randomly) and that value is stored into a TVar. As the execution time for generating the Fibonacci is different for different number, thus threads will not run sequentially. I want to store theadID, may be in a list, to check their execution pattern.
Please help me. Thanks in advance.
module Main
where
import Control.Parallel
import Control.Concurrent.STM
import Control.Concurrent
import System.Random
import Control.Monad
import Data.IORef
import System.IO
nfib :: Int -> Int
nfib n | n <= 2 = 1
| otherwise = par n1 (pseq n2 (n1 + n2 ))
where n1 = nfib (n-1)
n2 = nfib (n-2)
type TInt = TVar Int
updateNum :: TInt -> Int -> STM()
updateNum n v = do x1 <- readTVar n
let y = nfib v
x2 <- readTVar n
if x1 == x2
then writeTVar n y
else retry
updateTransaction :: TInt -> Int -> IO ()
updateTransaction n v = do atomically $ updateNum n v
incR :: IORef Int -> Int -> IO ()
incR r x = do { v <- readIORef r;
writeIORef r (v - x) }
main :: IO ()
main = do
n <- newTVarIO 10
r <- newIORef 40;
forM_ [1..10] (\i -> do
incR r i
;v <- readIORef r
;forkIO (updateTransaction n v)
)
I want to store [TreadID,FibNo] into a List for all the threads as per their execution. Suppose T1 has executed Fib30, T2 Fib35, T3->32 and T4->40. And if the commit sequence of threads like T1,T3, T2 and T4 then I want to store T1-35,T3-32,t2-35,t4-40 in a list.
Edit:
As suggested by #MathematicalOrchid, I have modified updateTrasaction as follows:-
updateTransaction :: MVar [(ThreadId, Int)] -> TInt -> Int -> IO ()
updateTransaction mvar n v = do
tid <- myThreadId
atomically $ updateNum n v
list <- takeMVar mvar
putMVar mvar $ list ++ [(tid, v)]
Now I am trying to print the values from that list in main
main :: IO ()
main = do
...
...
m <- newEmptyMVar
...
...
mv <- readMVar m
putStrLn ("ThreadId, FibVal : " ++ " = " ++ (show mv))
At the time of execution. MVar values couldn't be read and generates error
Exception: thread blocked indefinitely in an MVar operation
What to do? Thank in advance.
Did you want something like
updateTransaction :: TInt -> Int -> IO ()
updateTransaction n v = do
tid <- myThreadId
putStrLn $ "Start " ++ show tid
atomically $ updateNum n v
putStrLn $ "End " ++ show tid
Or perhaps something like
updateTransaction :: TInt -> Int -> IO ThreadId
updateTransaction n v = do
atomically $ updateNum n v
myThreadId
and change forM_ to forM?
Also, this part:
do
x1 <- readTVar n
...
x2 <- readTVar n
if x1 == x2 ...
If x1 /= x2 then GHC will automatically abort and restart your transaction. You do not need to manually check this yourself. Indeed, the else-branch can never execute. That's kind of the point of STM; it will appear to your transaction that nobody else changes the data you're looking at, so you don't ever have to worry about concurrent writes.
Edit: If you want to record the actual order in which the transactions committed, you're going to need some more inter-thread communication. Obviously you could do that with STM, but just for a list of stuff, maybe this could work?
updateTransaction :: MVar [(ThreadId, Int)] -> TInt -> Int -> IO ()
updateTransaction mvar n v = do
tid <- myThreadId
fib <- atomically $ updateNum n v
list <- takeMVar mvar
putMVar mvar $ list ++ [(tid, fib)]
(Obviously you have to make updateNum return the number it calculated.)
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