我是haskell的新手,我有以下代码
module StateTest where
import Control.Monad.State.Lazy
tick :: State Int Int
tick = do n <- get
put (n+1)
return n
plusOne :: Int -> Int
plusOne = execState tick
main = print $ plusOne 1
我想在put (n+1)
之后打印状态值并继续像这样计算
tick = do n <- get
put (n+1)
print
return n
整个代码如何看待这个?
答案 0 :(得分:5)
如果要在状态计算中运行IO操作,可以更改tick
的类型以返回StateT Int IO Int
并使用liftIO
。然后,您可以使用execStateT
:
import Control.Monad.State.Lazy
import Control.Monad.IO.Class (liftIO)
tick :: StateT Int IO Int
tick = do n <- get
put (n+1)
liftIO $ print (n+1)
return n
plusOne :: Int -> IO Int
plusOne = execStateT tick
main = plusOne 1 >> pure ()
答案 1 :(得分:0)
另一种选择,因为你必须使用IO
来打印中间状态的值,才能使用IORef
。它是一个具有可更新值的容器。
module Main where
import Data.IORef
tick :: IORef Int -> IO (IORef Int)
tick ref = do
modifyIORef' ref (+1)
-- you can also print here since it is IO
pure ref
main :: IO ()
main = do
counter <- newIORef 0
tick counter
v2 <- readIORef counter
print v2
tick counter
v2 <- readIORef counter
print v2
然后,您可以使用ReaderT
清除它。
module Main where
import Data.IORef
import Control.Monad.Reader
readerTick :: ReaderT (IORef Int) IO ()
readerTick = do
ref <- ask
-- can also print here with liftIO $ print ...
liftIO $ modifyIORef' ref (+1)
main :: IO ()
main = do
counter <- newIORef 0
runReaderT readerTick counter
v1 <- readIORef counter
print v1
runReaderT readerTick counter
v2 <- readIORef counter
print v2