假设我有一个状态monad,我想对状态进行一些操作,并且可能希望在将来撤消更改.我一般可以这样做得体面吗?
举一个具体的例子,让我们假设状态只是一个Int,操作就是将数字增加一个.
type TestM a = StateT a IO ()
inc :: TestM Int
inc = modify (+ 1)
Run Code Online (Sandbox Code Playgroud)
但是,如果我想跟踪状态的所有历史记录,以防我想要撤消到某个先前的状态,我能想到的最好的方法是将状态包装在堆栈中:对状态的每次修改都会被推送到堆栈,以便我可以通过删除堆栈上的顶部元素来撤消更改.
-- just for showing what's going on
traceState :: (MonadIO m, MonadState s m, Show s) => m a -> m a
traceState m = get >>= liftIO . print >> m
recordDo :: TestM a -> TestM [a]
recordDo m = do
x <- gets head
y <- liftIO $ execStateT m x
modify (y:)
inc' :: …Run Code Online (Sandbox Code Playgroud) 前言
我试图围绕如何实际使用ContT和callCC有用的东西.我无法跟踪代码周围的信息和控制流程.(但是,这不是延续的意义吗?)
有很多不同的方法可以用这个monad和少量非常直接的组合器来移动碎片.我将承认我对ContT的工作方式的理解仍感到不安,但我会指出我到目前为止所阅读的内容:
我想做的是发布一个psudo-code示例,然后询问一些有关它的问题.这代表使用ContT的典型代码外观
Psudo码
type MyMonad r = ContT r (State SomeState)
main = do
runState s_init $ runContT block print
block :: MyMonad r a0
block = do
before_callcc
output <- callCC $ \k -> do
rval <- inner_block
return rval
after_callcc
Run Code Online (Sandbox Code Playgroud)
问题
output?b这种类型的意思是k什么?k哪里?inner_block运行?它看到的是什么版本的州?rval去了,它的类型是什么?k和之间有什么关系rval? …我尝试为Continuation Monad Transformer的MonadWriter创建一个派生实例.这是我尝试的方式:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
import Control.Monad.Cont
import Control.Monad.Writer
instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell= lift . tell
listen m= ContT $ \ c -> do
(a,w) <- listen $ runContT m (c)
return (a,w)
pass m = undefined
Run Code Online (Sandbox Code Playgroud)
这给了我以下错误:
Occurs check: cannot construct the infinite type: r = (r, w1)
When generalising the type(s) for `listen'
In the instance declaration for `MonadWriter w (ContT r m)'
Run Code Online (Sandbox Code Playgroud)
接下来尝试是这样的:
instance (MonadWriter …Run Code Online (Sandbox Code Playgroud) 此功能允许您"跳回"到计算中的早期,获取参数,以便您可以采取不同的方式:
import Control.Monad.Cont
import Control.Monad.State.Strict
import Control.Monad.Writer.Strict
getCC' :: MonadCont m => a -> m (a,a -> m b)
getCC' x0 = callCC (\c -> let f x = c (x, f) in return (x0, f))
Run Code Online (Sandbox Code Playgroud)
我有这些monad变换器的玩具示例Cont:
foo :: WriterT String (Cont String) ()
foo = do
(stop,loop) <- getCC' False
if stop
then do tell "bbb"
else do tell "aaa"
loop True
foo' :: StateT String (Cont String) ()
foo' = …Run Code Online (Sandbox Code Playgroud) 我写了这段代码:
toCouplesFile = do inputFile <- openFile "deletedId.csv" ReadMode
outputFile <- openFile "couples.txt" WriteMode
readAndChange inputFile outputFile
readAndChange i o = do iseof <- hIsEOF i
if iseof then (return o)
else do line <- hGetLine i
hPutStrLn o (show (extractNameAndId line))
readAndChange i o
Run Code Online (Sandbox Code Playgroud)
我想知道是否可以使用一个函数重写此代码,使用类似于此模式的东西:
function x = do ...
label
.....
if ... then label else exit
Run Code Online (Sandbox Code Playgroud)