在 ST monad 和 runSTUArray 中使用 IO

Using IO inside the ST monad and runSTUArray

我刚开始尝试使用 monad 转换器,所以我可能漏掉了一些微不足道的东西。无论如何:如何从 ST monad 内部打印?

示例代码:我想创建几乎与 C 一样快的代码,通过尽可能快地读写内存,使用类似 C 的 for 循环。我有一个 ST monad 动作,可以安全地改变一个未装箱的数组,我 运行 和 runSTUArray.

我的问题是,如何在 ST 动作中使用 IO 动作?如果它是一个 State monad 动作,我可以使用 StateT 转换器将 IO 动作提升到,但是 ST monad 是怎么做到的?

示例:ST。 -- 如何在 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

示例:StateT,-- 这里可以提升 print 以在 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))])

您不是从 ST 操作打印,而是从 IO 操作打印。幸运的是,引擎盖下有 IOUArrays -- and they are even STUArrays,因此不必担心性能下降。