我在Haskell中有这个代码:
import Control.Monad.Trans.State
simpleState = state (\x -> (x, x + 1))
runUntil :: (s -> Bool) -> State s a -> State s a
runUntil f s = do
s' <- get
-- Here I want to print value of s' to console
if f s'
then s >> runUntil f s
else s
main :: IO ()
main = do
let (x,s) = runState (runUntil (< 10) simpleState) 0
putStrLn $ "State = " ++ (show s) ++ " Result = " ++ (show x)
Run Code Online (Sandbox Code Playgroud)
我想在runUntil的每次迭代中打印状态的值.
如果我不能在runUntil
功能上打印它我可以做到这一点?
Dan*_*zer 11
欢迎来到Monad变形金刚的精彩世界.有一个很好的库叫MTL,提供大多数monad的"monad transformer"等价物.按照惯例,这些以大写字母T结束,StateT
我们想要的也是如此.Monad的变压器具有其通常的操作和多一个,lift
为一个StateT
看起来像这样,
lift :: Monad m => m a -> StateT s m a
Run Code Online (Sandbox Code Playgroud)
现在有一个特殊的变压器类在IO
被调用之上MonadIO
.要使用它,我们会做类似的事情.它类似于一个普通的旧monad变换器,但具有类型签名
liftIO :: (MonadIO m, Monad m) => IO a -> m a
import Control.Monad.State
import Control.Monad.Trans
simpleState :: StateT Integer IO ()
simpleState = modify (+1)
runUntil :: Show s => (s -> Bool) -> StateT s IO a -> StateT s IO s
runUntil pred newState = do
curr <- get
if pred curr
then liftIO (print curr) >> newState >> runUntil pred newState
else return curr
Run Code Online (Sandbox Code Playgroud)
然后运行它,有一套方便的函数可以转换StateT s m a
成s -> (s, a)
.
main :: IO ()
main = do
(x,s) <- runStateT (runUntil (< 10) simpleState) 0
putStrLn $ "State = " ++ (show s) ++ " Result = " ++ (show x)
Run Code Online (Sandbox Code Playgroud)
请注意,现在我们使用bind(the <-
)因为结果是IO
,它不再是纯粹的.Monad变形金刚可能会让人感到困惑,幸运的是,Real World Haskell有一章介绍它们.如果你感到困惑,那值得一看.