以下程序使用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]

最佳答案

现在,我已经下载了TardisRevState的源代码,并开始对其进行黑客攻击,直到它们几乎相同为止:

  • 我忽略了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使用程序。

    10-01 11:33