以下程序使用Tardis monad提供的向后移动状态。
{-# LANGUAGE RecursiveDo #-}
import Control.Monad.Tardis
lastOccurrence :: Int -> Tardis [Int] () Bool
lastOccurrence x = mdo
sendPast (x : xs)
xs <- getFuture
return (not (elem x xs))
lastOccurrences :: [Int] -> Tardis [Int] () [Bool]
lastOccurrences xs = mapM lastOccurrence xs
main :: IO ()
main =
print $ flip evalTardis ([], ()) $ lastOccurrences [3,4,6,7,4,3,5,7]
如何用reverse State monad代替Tardis monad?
根据我的以下建议,
main
永远循环而不是打印[False,False,True,False,True,True,True,True]
与上述程序相同。{-# LANGUAGE RecursiveDo #-}
import Control.Monad.RevState
lastOccurrence :: Int -> State [Int] Bool
lastOccurrence x = mdo
put (x : xs)
xs <- get
return (not (elem x xs))
lastOccurrences :: [Int] -> State [Int] [Bool]
lastOccurrences xs = mapM lastOccurrence xs
main :: IO ()
main =
print $ flip evalState [] $ lastOccurrences [3,4,6,7,4,3,5,7]
最佳答案
现在,我已经下载了Tardis
和RevState
的源代码,并开始对其进行黑客攻击,直到它们几乎相同为止:
Trans.{Tarids,RevState}
模块之外的所有内容,因此不必麻烦Tardis
的向前传播状态Tardis
重命名为State
在对代码进行了一些重新排序之后,我遇到了以下情况:您的
Tardis
-使用示例仍然有效,而您的RevState
-using示例仍然无效,并且它们之间的差异很小。你问最小的区别是什么?毫不奇怪,
MonadFix
实例。 Tardis
has this:instance MonadFix m => MonadFix (TardisT bw fw m) where
mfix f = TardisT $ \s -> do
rec (x, s') <- runTardisT (f x) s
return (x, s')
而
RevState
has this:instance MonadFix m => MonadFix (StateT s m) where
mfix f = StateT $ \s ->
mfix (\(x, _) -> runStateT (f x) s)
尽管它们看起来很相似,但是最大的区别是,在元组构造函数中
RevState
一个是严格的,而Tardis
一个是惰性的。 (例如,参见GHC documentation on RecursiveDo
,以查看Tardis
在传递给mfix
的lambda中将一个desugars变成了不可辩驳的模式匹配)。确实,更改了
RevState
的实现,以便instance MonadFix m => MonadFix (StateT s m) where
mfix f = StateT $ \s -> do
mfix (\ ~(x, _) -> runStateT (f x) s)
修复您的原始
RevState
使用程序。