tardis 0.4.4.0 → 0.5.0.1
raw patch · 9 files changed
Files
- ChangeLog.md +3/−0
- LICENSE +1/−1
- README.md +34/−0
- src/Control/Monad/Tardis.hs +4/−4
- src/Control/Monad/Tardis/Class.hs +9/−11
- src/Control/Monad/Trans/Tardis.hs +15/−17
- tardis.cabal +6/−7
- test/Example.hs +10/−11
- test/Main.hs +3/−1
+ ChangeLog.md view
@@ -0,0 +1,3 @@+* **0.5.0**:+ 2024-01-15: Removed MonadTrans instance, replaced with liftTardisT+
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012, Dan Burton+Copyright (c) 2012-2026, Dan Burton All rights reserved.
+ README.md view
@@ -0,0 +1,34 @@+# TardisT++++The State monad allows you+to send information forwards to the future,+or to receive such information from the past.+The Reverse State monad allows you to do the reverse:+send information backwards to the past,+or receive information from the future. ++TardisT is a monad transformer+that provides state operations that allow you+to send information to both the future *and* the past,+as well as receive information from both directions.+It is isomorphic to a StateT on top of a ReverseStateT,+or vice-versa.++See test/Example.hs for an example.++----++This was inspired by Luke Palmer's blog post on+the "reverse state monad".++http://lukepalmer.wordpress.com/2008/08/10/mindfuck-the-reverse-state-monad/++See also:++http://panicsonic.blogspot.com/2007/12/backwards-state-or-power-of-laziness.html++----++(c) 2012-2026 Dan Burton
src/Control/Monad/Tardis.hs view
@@ -61,14 +61,14 @@ while setting the backwards-traveling state will affect the /past/. Take a look at how Monadic bind is implemented for 'TardisT': -> m >>= f = TardisT $ \ ~(bw, fw) -> do-> rec (x, ~(bw'', fw' )) <- runTardisT m (bw', fw)-> (x', ~(bw' , fw'')) <- runTardisT (f x) (bw, fw')+> m >>= f = TardisT $ \ ~(bw, fw) -> mdo+> (x, ~(bw'', fw' )) <- runTardisT m (bw', fw)+> (x', ~(bw' , fw'')) <- runTardisT (f x) (bw, fw') > return (x', (bw'', fw'')) Like the Reverse State monad transformer, TardisT's Monad instance requires that the monad it transforms is an instance of MonadFix,- as is evidenced by the use of @rec@.+ as is evidenced by the use of @mdo@. Notice how the forwards-traveling state travels /normally/: first it is fed to @m@, producing @fw'@, and then it is fed to @f x@, producing @fw''@. The backwards-traveling state travels in the opposite
src/Control/Monad/Tardis/Class.hs view
@@ -66,13 +66,12 @@ -- | A Tardis is merely a pure state transformation. tardis :: ((bw, fw) -> (a, (bw, fw))) -> m a- tardis f = do- rec- let (a, (future', past')) = f (future, past)- sendPast future'- past <- getPast- future <- getFuture- sendFuture past'+ tardis f = mdo+ let (a, (future', past')) = f (future, past)+ sendPast future'+ past <- getPast+ future <- getFuture+ sendFuture past' return a -- | Modify the forwards-traveling state@@ -83,10 +82,9 @@ -- | Modify the backwards-traveling state -- as it passes through from future to past. modifyBackwards :: MonadTardis bw fw m => (bw -> bw) -> m ()-modifyBackwards f = do- rec- sendPast (f x)- x <- getFuture+modifyBackwards f = mdo+ sendPast (f x)+ x <- getFuture return () -- | Retrieve a specific view of the forwards-traveling state.
src/Control/Monad/Trans/Tardis.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE RecursiveDo #-}+{-# LANGUAGE TupleSections #-} -- | The data definition of a "TardisT" -- as well as its primitive operations,@@ -35,6 +36,7 @@ -- * Other , mapTardisT+ , liftTardisT , noState ) where @@ -99,6 +101,10 @@ execTardis :: Tardis bw fw a -> (bw, fw) -> (bw, fw) execTardis t = runIdentity . execTardisT t +-- | An action in the underlying monad (or just functor, really)+-- can also be used in a Tardis by lifting it in.+liftTardisT :: (Functor m) => m a -> TardisT bw fw m a+liftTardisT m = TardisT $ \s -> fmap (,s) m -- | A function that operates on the internal representation of a Tardis -- can also be used on a Tardis.@@ -119,28 +125,21 @@ ------------------------------------------------- instance MonadFix m => Monad (TardisT bw fw m) where- return x = tardis $ \s -> (x, s)- m >>= f = TardisT $ \ ~(bw, fw) -> do- rec (x, ~(bw'', fw' )) <- runTardisT m (bw', fw)- (x', ~(bw' , fw'')) <- runTardisT (f x) (bw, fw')+ m >>= f = TardisT $ \ ~(bw, fw) -> mdo+ (x, ~(bw'', fw' )) <- runTardisT m (bw', fw)+ (x', ~(bw' , fw'')) <- runTardisT (f x) (bw, fw') return (x', (bw'', fw'')) instance MonadFix m => Functor (TardisT bw fw m) where fmap = liftM instance MonadFix m => Applicative (TardisT bw fw m) where- pure = return+ pure x = tardis $ \s -> (x, s) (<*>) = ap --instance MonadTrans (TardisT bw fw) where- lift m = TardisT $ \s -> do- x <- m- return (x, s)- instance MonadFix m => MonadFix (TardisT bw fw m) where- mfix f = TardisT $ \s -> do- rec (x, s') <- runTardisT (f x) s+ mfix f = TardisT $ \s -> mdo+ (x, s') <- runTardisT (f x) s return (x, s') instance MFunctor (TardisT bw fw) where@@ -194,10 +193,9 @@ -- | Modify the backwards-traveling state -- as it passes through from future to past. modifyBackwards :: MonadFix m => (bw -> bw) -> TardisT bw fw m ()-modifyBackwards f = do- rec- sendPast (f x)- x <- getFuture+modifyBackwards f = mdo+ sendPast (f x)+ x <- getFuture return ()
tardis.cabal view
@@ -1,5 +1,5 @@ name: tardis-version: 0.4.4.0+version: 0.5.0.1 synopsis: Bidirectional state monad transformer homepage: https://github.com/DanBurton/tardis bug-reports: https://github.com/DanBurton/tardis/issues@@ -10,6 +10,8 @@ category: Control build-type: Simple cabal-version: >=1.10+tested-with: GHC == 9.14.1, GHC == 9.12.2, GHC == 9.10.3, GHC == 9.8.4, GHC == 9.6.7, GHC == 9.4.8+extra-source-files: README.md, ChangeLog.md description: A Tardis is a combination of both a forwards and a backwards@@ -30,6 +32,7 @@ build-depends: base >= 4.8 && < 5 , mtl==2.* , mmorph==1.*+ ghc-options: -Wcompat -Wall -Wno-unused-imports test-suite tardis-tests default-language: Haskell2010@@ -39,12 +42,8 @@ build-depends: base >= 4.8 && < 5 , tardis other-modules: Example+ ghc-options: -Wcompat -Wall -Wno-unrecognised-warning-flags -Wno-x-partial source-repository head type: git- location: git://github.com/DanBurton/tardis.git--source-repository this- type: git- location: git://github.com/DanBurton/tardis.git- tag: tardis-0.4.1.0+ location: https://github.com/DanBurton/tardis.git
test/Example.hs view
@@ -38,17 +38,16 @@ PreviousScores scores <- getPast let score = head scores return $ (finalFrameScore + score) : scores- go (f : fs) = do- rec- sendPast $ NextThrows throws'- PreviousScores scores <- getPast- let score = head scores- sendFuture $ PreviousScores (score' : scores)- NextThrows ~(nextThrow1, nextThrow2) <- getFuture- let (score', throws') = case f of- Strike -> (score + 10 + nextThrow1 + nextThrow2, (10, nextThrow1))- Spare n -> (score + 10 + nextThrow1, (n, 10 - n))- Frame n m -> (score + n + m, (n, m))+ go (f : fs) = mdo+ sendPast $ NextThrows throws'+ PreviousScores scores <- getPast+ let score = head scores+ sendFuture $ PreviousScores (score' : scores)+ NextThrows ~(nextThrow1, nextThrow2) <- getFuture+ let (score', throws') = case f of+ Strike -> (score + 10 + nextThrow1 + nextThrow2, (10, nextThrow1))+ Spare n -> (score + 10 + nextThrow1, (n, 10 - n))+ Frame n m -> (score + n + m, (n, m)) go fs finalFrameScore = case lastFrame game of
test/Main.hs view
@@ -7,4 +7,6 @@ putStrLn $ "Expected: " <> show expectedScores putStrLn $ "Actual: " <> show actualScores exitFailure- True -> exitSuccess+ True -> do+ putStrLn "Test passed."+ exitSuccess