I'm just starting to experiment with monad transformers so I may have missed something trivial. Anyway: how can I print from inside the ST monad?
Example code: I want to create code that is almost as fast as C, by reading and writing as quickly as possible to memory, with C-like for loops. I have an ST
monad action that safely mutates an unboxed array that I run with runSTUArray
.
My question is, how can I use IO
actions inside the ST
action? If it was a State
monad action, I could use the StateT
transformer to lift the IO
actions to, but how is that done for the ST
monad?
Example: ST. -- how can I print form inside the ST monad?
import Control.Monad.ST (ST)
import Data.Array.Base ( STUArray(STUArray), newArray, readArray, writeArray )
import Data.Array.ST (runSTUArray)
import Data.Array.Unboxed ( elems )
import Control.Monad (forM_)
test :: IO ()
test = print . elems $ runSTUArray action
where
action :: ST s (STUArray s Int Int)
action = do
arr <- newArray (1,10) 1
forM_ [3..10] $ \i -> do
-- liftIO . print $ "i is " show i. --- <--- How should I do this?
x1 <- readArray arr (i-1)
x2 <- readArray arr (i-2)
writeArray arr i (x1 x2)
return arr
Example: StateT, -- here it is possible to lift the print
to use it inside the monad/
import Data.Array.IArray (listArray, (!), (//), elems)
import Data.Array (Array)
import Control.Monad.Trans.State.Strict (StateT (runStateT), get, put)
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad (forM_)
test :: IO ()
test = do
let n = listArray (1,10) [1..] :: Array Int Int
(_,x) <- runStateT action n
print $ elems x
return ()
where action = do
forM_ [3..10] $ \i -> do
x <- get
liftIO . print $ "i is " show i. -- <--- here printing works fine
put (x // [(i, x!(i-1) x!(i-2))])
CodePudding user response:
You don't print from an ST
action, you print from an IO
action. Luckily for you, there are IOUArray
s -- and they are even STUArray
s under the hood, so there can be no fear of performance lost.