Haskell 中的逆因果关系:从 Tardis 到 RevState
Retrocausality in Haskell: From Tardis to RevState
以下程序使用 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
-using 示例仍然有效而你的 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')
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 中脱糖成无可辩驳的模式匹配)。
确实,更改 RevState
的实现,以便
instance MonadFix m => MonadFix (StateT s m) where
mfix f = StateT $ \s -> do
mfix (\ ~(x, _) -> runStateT (f x) s)
修复您原来的 RevState
-using 程序。
以下程序使用 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
-using 示例仍然有效而你的 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')
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 中脱糖成无可辩驳的模式匹配)。
确实,更改 RevState
的实现,以便
instance MonadFix m => MonadFix (StateT s m) where
mfix f = StateT $ \s -> do
mfix (\ ~(x, _) -> runStateT (f x) s)
修复您原来的 RevState
-using 程序。