failback monad

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
data Repeat a= ICanRepeat a | NoRepeat a | RepeatPlease deriving Typeable

newtype BackT m a = BackT { runBackT :: m (Repeat a) }

The monad instance is as long as NoRepeat is used, similar to what would be an identity monad transformer. But when RepeatPlease is found, the monad roll back until an ICanRepeat statement is found and start again from it. 

instance (Monad m) => Monad (BackT m) where
    fail   _ = BackT (return RepeatPlease)
    return x = BackT . return $ NoRepeat x
    x >>= f  = BackT $ loop
     where
     loop= do
        v <- runBackT x
        case v of
            NoRepeat y  -> runBackT (f y)

            RepeatPlease -> return RepeatPlease
            ICanRepeat y  -> do
                 z <- runBackT (f y)
                 case z of
                  RepeatPlease -> loop
                  other -> return other

            

liftRepeat f= BackT $ f >>= \x -> return $ ICanRepeat x