Say that I have a State monad, and I want to do some manipulations on the state and might want to undo the change in future. How in general can I do this decently?
To give a concrete example, let's assume the state is just an Int, and the manipulation
is just to increase the number by one.
type TestM a = StateT a IO ()
inc :: TestM Int
inc = modify (+ 1)
however, if I want to keep track of all the history of states in case I want to undo to some previous state, the best I can think of is to wrap the states in a stack: every modification to the state will be pushed to the stack so that I can undo changes through droping the top element on the stack.
-- just for showing what's going on
traceState :: (MonadIO m, MonadState s m, Show s) => m a -> m a
traceState m = get >>= liftIO . print >> m
recordDo :: TestM a -> TestM [a]
recordDo m = do
x <- gets head
y <- liftIO $ execStateT m x
modify (y:)
inc' :: TestM [Int]
inc' = recordDo inc
undo' :: TestM [Int]
undo' = modify tail
-- inc 5 times, undo, and redo inc
manip' :: TestM [Int]
manip' = mapM_ traceState (replicate 5 inc' ++ [undo',inc'])
main :: IO ()
main = do
v1 <- execStateT (replicateM_ 5 (traceState inc)) 2
v2 <- execStateT (replicateM_ 5 (traceState inc')) [2]
v3 <- execStateT manip' [2]
print (v1,v2,v3)
As expected, here is the output:
2
3
4
5
6
[2]
[3,2]
[4,3,2]
[5,4,3,2]
[6,5,4,3,2]
[2]
[3,2]
[4,3,2]
[5,4,3,2]
[6,5,4,3,2]
[7,6,5,4,3,2]
[6,5,4,3,2]
(7,[7,6,5,4,3,2],[7,6,5,4,3,2])
The drawback of my approach:
tail and head are unsafe
One have to use something like recordDo explicitly, but I guess this is unavoidable because otherwise there will be some inconsistency issue. For example increasing the number by two can be done by either inc' >> inc' or recordDo (inc >> inc) and these two approach have different effects on the stack.
So I'm looking for either some ways to make it more decent or something that does the job of "reversible state" better.
Depending on your use-case, it might be worth considering something that I'd call "delimited undo":
{-# LANGUAGE FunctionalDependencies, FlexibleContexts #-}
import Control.Applicative
import Control.Monad
import Control.Monad.State
import Control.Monad.Trans.Maybe
undo :: (MonadState s m, MonadPlus m) => m a -> m a -> m a
undo dflt k = do
s <- get
k `mplus` (put s >> dflt)
undoMaybe :: (MonadState s m) => m a -> MaybeT m a -> m a
undoMaybe dflt k = do
s <- get
r <- runMaybeT k
maybe (put s >> dflt) return r
undoMaybe_ :: (MonadState s m) => MaybeT m () -> m ()
undoMaybe_ = undoMaybe (return ())
Executing undo x k means "execute k, and if it fails, undo the state and execute x instead". Function undoMaybe works similarly, but allows the failure only the nested block. Your example then could be expressed as:
type TestM a = StateT a IO ()
inc :: (MonadState Int m) => m ()
inc = modify (+ 1)
-- just for showing what's going on
traceState :: (MonadIO m, MonadState s m, Show s) => m a -> m a
traceState m = get >>= liftIO . print >> m
inc' :: (MonadIO m, MonadState Int m) => m ()
inc' = traceState inc
-- inc 5 times, undo, and redo inc
manip' :: TestM Int
manip' = replicateM 4 inc' >> undoMaybe_ (inc' >> traceState mzero) >> inc'
main :: IO ()
main = do
v1 <- execStateT (replicateM_ 5 (traceState inc)) 2
putStrLn ""
v3 <- execStateT manip' 2
print (v1,v3)
The main advantage is that you can never underflow the stack. The disadvantage is that you can't access the stack and the undo is always delimited.
One could also create an Undo monad transformer that where the above undo becomes mplus. Whenever a failed computation is restored with mplus, the state is restored as well.
newtype Undo m a = Undo (m a)
deriving (Functor, Applicative, Monad)
instance MonadTrans Undo where
lift = Undo
instance (MonadState s m) => MonadState s (Undo m) where
get = lift get
put = lift . put
state = lift . state
instance (MonadPlus m, MonadState s m) => MonadPlus (Undo m) where
mzero = lift mzero
x `mplus` y = do
s <- get
x `mplus` (put s >> y)
Related
I'm writing interpreter in haskell. I want to do that with monads.
I already created parser, so I have a lot of functions :: State -> MyMonad State, and I can run my program using bind. m >>= inst1 >>= inst2.
Everything works perfectly fine, but I have no idea how to create instruction print (or read) in my language with that monad.
I don't want simple, but ugly, solutions like keeping strings to print inside State and printing in main at the end. (What if I have infinity while with print?)
I couldn't understand texts from web about that part of monad functionality. There were some explanations like "pack inside IO Monad, it's quite straightforward", but without any working examples. And almost all printing tutorials was about printing in main.
To better explain problem, I prepared minimal "interpreter" example (below). There State is just Int, my monad is AutomatM instructions have type :: Int -> AutomatM Int. So possible instruction is:
inc :: Int -> AutomatM Int
inc x = return (x+1)
I designed it as simple as I could think:
import Control.Applicative
import Control.Monad (liftM, ap)
import Control.Monad.IO.Class (MonadIO(..))
import System.IO
data AutomatM a = AutomatError | Running a
instance Show a => Show (AutomatM a) where
show (AutomatError) = "AutomatError"
show (Running a) = "Running " ++ show a
instance Functor AutomatM where
fmap = liftM
instance Applicative AutomatM where
pure = return
(<*>) = ap
instance Monad AutomatM where
return x = Running x
m >>= g = case m of
AutomatError -> AutomatError
Running x -> g x
magicPrint x = do
-- print x -- How can I make print work?
-- c <- getLine -- And if that is as simple as print
b <- return "1000" -- how can I change constant to c?
return (x + (read b :: Int))
main = do
a <- getLine
print $ (Running (read a :: Int)) >>= (\x -> return (x*2)) >>= magicPrint
My main target is to add print x inside magicPrint. However if it's not harder, it would be nice to have getLine.
I changed state in magicPrint, because print in my language has side effects.
I know that I need something with monad transformers and maybe MonadIO, but it's hard to find any tutorial with simple explanation for beginners.
Therefore I would very appreciate extending my minimal code example to work with prints (and maybe getLine/other read Int) and some explanations to that (perhaps with links).
Functor and Aplicative code is based on Defining a new monad in haskell raises no instance for Applicative
In order to create a new type with a Monad instance and access IO form inside of it, you will need to create another monad transformer type called AutomatMT and declare an instance of Monad, MonadTrans, etc. for it. It involves a lot of boilerplate code. I'll try to clarify anything that doesn't make sense.
import Control.Applicative
import Control.Monad (liftM, ap)
import Control.Monad.IO.Class (MonadIO(..))
import System.IO
import Control.Monad.Trans.Class (MonadTrans(..), lift)
data AutomatM a = AutomatError | Running a
instance Show a => Show (AutomatM a) where
show (AutomatError) = "AutomatError"
show (Running a) = "Running " ++ show a
instance Functor AutomatM where
fmap = liftM
instance Applicative AutomatM where
pure = return
(<*>) = ap
instance Monad AutomatM where
return x = Running x
m >>= g = case m of
AutomatError -> AutomatError
Running x -> g x
newtype AutomatMT m a = AutomatMT { runAutomatMT :: m (AutomatM a) }
mapAutomatMT :: (m (AutomatM a) -> n (AutomatM b)) -> AutomatMT m a -> AutomatMT n b
mapAutomatMT f = AutomatMT . f . runAutomatMT
instance (Functor m) => Functor (AutomatMT m) where
fmap f = mapAutomatMT (fmap (fmap f))
instance MonadTrans AutomatMT where
lift = AutomatMT . liftM Running
instance (Functor m, Monad m) => Applicative (AutomatMT m) where
pure = AutomatMT . return . Running
mf <*> mx = AutomatMT $ do
mb_f <- runAutomatMT mf
case mb_f of
AutomatError -> return AutomatError
Running f -> do
mb_x <- runAutomatMT mx
case mb_x of
AutomatError -> return AutomatError
Running x -> return (Running (f x))
instance (MonadIO m) => MonadIO (AutomatMT m) where
liftIO = lift . liftIO
instance (Monad m) => Monad (AutomatMT m) where
x >>= f = AutomatMT $ do
v <- runAutomatMT x
case v of
AutomatError -> return AutomatError
Running y -> runAutomatMT (f y)
fail _ = AutomatMT (return AutomatError)
magicPrint :: String -> (AutomatMT IO String)
magicPrint x = do
liftIO $ print $ "You gave magic print " ++ x
let x = "12"
y <- pure 1
liftIO $ print y
pure $ "1"
main = do
print "Enter some text"
a <- getLine
b <- runAutomatMT $ magicPrint a
pure ()
I'm trying to implement a Maybe-State monad transformer and use it to implement a simple stack machine.
The definitions of state monad and maybe should be correct. Now I'm trying to implement pop:
pop :: MaybeT (State Stack) Int
So that if the stack is empty it returns nothing, otherwise it returns Just <popped stack>.
This is what I have so far:
pop :: MaybeT (State Stack) Int
pop = guard True (do (r:rs) <- get
put rs
return r)
(Obviously True is just a dummy placeholder - I'll implement the condition later, for now I want to get the other part right).
What is wrong with my code? From my understanding guard takes a conditional (True) and a function f. If the conditional is true it then gives pure f.
In my case,
pure = MaybeT . return . Just
So shouldn't my function f just return a State Stack Int?
Here is the full code, with my implementations of MaybeT and State:
import Control.Applicative (Alternative(..))
import Control.Monad (liftM, ap, guard)
import Control.Monad.Trans.Class (MonadTrans(lift))
main :: IO()
main = return ()
-- State Monad
--------------
newtype State s a = MakeState { runState :: s -> (a, s) }
instance Functor (State s) where
fmap = liftM
instance Applicative (State s) where
pure a = MakeState $ \s -> (a, s)
(<*>) = ap
instance Monad (State s) where
return a = MakeState $ \s -> (a, s)
m >>= k = MakeState $ \s -> let (x, s') = runState m s
in runState (k x) s'
get :: State s s
get = MakeState $ \s -> (s, s)
put :: s -> State s ()
put s = MakeState $ \_ -> ((), s)
modify :: (s -> s) -> State s ()
modify f = MakeState $ \s -> ((), f s)
-- MaybeT MonadTransformer
---------------------------
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
instance Monad m => Functor (MaybeT m) where
fmap a x = MaybeT $ do e <- runMaybeT x
return $ fmap a e
instance Monad m => Applicative (MaybeT m) where
pure = MaybeT . return . Just
(<*>) a b = MaybeT $ do e <- runMaybeT a
f <- runMaybeT b
return $ e <*> f
instance Monad m => Monad (MaybeT m) where
return = pure
a >>= b = MaybeT $ do aa <- runMaybeT a
maybe (return Nothing) (runMaybeT . b) aa
instance Monad m => Alternative (MaybeT m) where
empty = MaybeT $ return Nothing
a <|> b = MaybeT $ do aa <- runMaybeT a
bb <- runMaybeT b
return $ aa <|> bb
instance MonadTrans MaybeT where
-- "herwrappen" van het argument
lift x = MaybeT $ do r <- x
return $ Just r
-- Stack Manipulation
---------------------
type Stack = [Int]
-- plaats het argument bovenop de stack
push :: Int -> State Stack ()
push x = do r <- get
put (x:r)
-- geef de grootte van de stack terug
size :: State Stack Int
size = do r <- get
return $ length r
-- neem het eerste element van de stack, als het aanwezig is
-- (hint: hoogle naar `guard`)
pop :: MaybeT (State Stack) Int
pop = guard (True) (do (r:rs) <- get
put rs
return r)
guard doesn't take two arguments, it only takes a Bool argument.
You also need to lift your state manipulations into MaybeT:
pop :: MaybeT (State Stack) Int
pop = do
guard True
(r:rs) <- lift get
lift $ put rs
return r
First of all, you should understand if your stack is empty, your pattern r:rs <- get fails. But you write it in do-block, so the fail function will be called. It is implemented for Monad m => MaybeT m like this: fail _ = MaybeT (return Nothing). This means that if the pattern fails it returns Nothing. That what you want.
So, you can do like this:
pop :: MaybeT (State Stack) Int
pop = do r:rs <- get
put rs
return r
For the sake of comparison, here is a cruder implementation which doesn't rely neither on guard nor on fail:
pop :: MaybeT (State Stack) Int
pop = do
stk <- lift get
case stk of
[] -> empty
(r:rs) -> do
lift (put rs)
return r
Producing empty when the stack is [] amounts to the same thing that using guard in the way you intend, or using fail to exploit a failed pattern match (as in freestyle's answer).
I'm learning about mtl and I wish learn the proper way to create new monads as modules (not as typical application usage).
As a simple example I have written a ZipperT monad (complete code here):
{-# LANGUAGE FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
module ZipperT (
MonadZipper (..)
, ZipperT
, runZipperT
) where
import Control.Applicative
import Control.Monad.State
class Monad m => MonadZipper a m | m -> a where
pushL :: a -> m ()
pushR :: a -> m ()
...
data ZipperState s = ZipperState { left :: [s], right :: [s] }
newtype ZipperT s m a = ZipperT_ { runZipperT_ :: StateT (ZipperState s) m a }
deriving ( Functor, Applicative
, Monad, MonadIO, MonadTrans
, MonadState (ZipperState s))
instance (Monad m) => MonadZipper s (ZipperT s m) where
pushL x = modify $ \(ZipperState left right) -> ZipperState (x:left) right
pushR x = modify $ \(ZipperState left right) -> ZipperState left (x:right)
...
runZipperT :: (Monad m) => ZipperT s m a -> ([s], [s]) -> m (a, ([s], [s]))
runZipperT computation (left, right) = do
(x, ZipperState left' right') <- runStateT (runZipperT_ computation) (ZipperState left right)
return (x, (left', right'))
it's works and I can compose with other monads
import Control.Monad.Identity
import Control.Monad.State
import ZipperT
length' :: [a] -> Int
length' xs = runIdentity (execStateT (runZipperT contar ([], xs)) 0)
where contar = headR >>= \x -> case x of
Nothing -> return ()
Just _ -> do
right2left
(lift . modify) (+1)
-- ^^^^^^^
contar
But I wish to avoid the explicit lift.
What is the correct way to create modules like this?
Can I avoid the explicit lift? (I wish to hide the internal StateT structure of my ZipperT)
Thank you!
I think that if you can write an instance of MonadState for your transformer you can use modify without the lift:
instance Monad m => MonadState (ZipperT s m a) where
...
I must confess I am not sure about what part of the state modify should affect, though.
I've looked at the complete code. It seems that you already define
MonadState (ZipperState s) (ZipperT s m)
This already provides a modify which however modifies the wrong underlying state. What you actually wanted was to expose the state wrapped in m, provided that is a MonadState itself. This could theoretically be done with
instance MonadState s m => MonadState s (ZipperT s m) where
...
But now we have two MonadState instances for the same monad, causing a conflict.
I think I somehow solved this.
Here's what I did:
First, I removed the original deriving MonadState instance. I instead wrote
getZ :: Monad m => ZipperT s m (ZipperState s)
getZ = ZipperT_ get
putZ :: Monad m => ZipperState s -> ZipperT s m ()
putZ = ZipperT_ . put
modifyZ :: Monad m => (ZipperState s -> ZipperState s) -> ZipperT s m ()
modifyZ = ZipperT_ . modify
and replaced previous occurrences of get,put,modify in the ZipperT library with the above custom functions.
Then I added the new instance:
-- This requires UndecidableInstances
instance MonadState s m => MonadState s (ZipperT a m) where
get = lift get
put = lift . put
And now, the client code works without lifts:
length' :: [a] -> Int
length' xs = runIdentity (execStateT (runZipperT contar ([], xs)) 0)
where contar :: ZipperT a (StateT Int Identity) ()
contar = headR >>= \x -> case x of
Nothing -> return ()
Just _ -> do
right2left
modify (+ (1::Int))
-- ^^^^^^^
contar
Context: This question is specifically in reference to Control.Lens (version 3.9.1 at the time of this writing)
I've been using the lens library and it is very nice to be able to read and write to a piece (or pieces for traversals) of a structure. I then had a though about whether a lens could be used against an external database. Of course, I would then need to execute in the IO Monad. So to generalize:
Question:
Given a getter, (s -> m a) and an setter (b -> s -> m t) where m is a Monad, is possible to construct Lens s t a b where the Functor of the lens is now contained to also be a Monad? Would it still be possible to compose these with (.) with other "purely functional" lenses?
Example:
Could I make Lens (MVar a) (MVar b) a b using readMVar and withMVar?
Alternative:
Is there an equivalent to Control.Lens for containers in the IO monad such as MVar or IORef (or STDIN)?
I've been thinking about this idea for some time, which I'd call mutable lenses. So far, I haven't made it into a package, let me know, if you'd benefit from it.
First let's recall the generalized van Laarhoven Lenses (after some imports we'll need later):
{-# LANGUAGE RankNTypes #-}
import qualified Data.ByteString as BS
import Data.Functor.Constant
import Data.Functor.Identity
import Data.Traversable (Traversable)
import qualified Data.Traversable as T
import Control.Monad
import Control.Monad.STM
import Control.Concurrent.STM.TVar
type Lens s t a b = forall f . (Functor f) => (a -> f b) -> (s -> f t)
type Lens' s a = Lens s s a a
we can create such a lens from a "getter" and a "setter" as
mkLens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
mkLens g s f x = fmap (s x) (f (g x))
and get a "getter"/"setter" from a lens back as
get :: Lens s t a b -> (s -> a)
get l = getConstant . l Constant
set :: Lens s t a b -> (s -> b -> t)
set l x v = runIdentity $ l (const $ Identity v) x
as an example, the following lens accesses the first element of a pair:
_1 :: Lens' (a, b) a
_1 = mkLens fst (\(x, y) x' -> (x', y))
-- or directly: _1 f (a,c) = (\b -> (b,c)) `fmap` f a
Now how a mutable lens should work? Getting some container's content involves a monadic action. And setting a value doesn't change the container, it remains the same, just as a mutable piece of memory does. So the result of a mutable lens will have to be monadic, and instead of the return type container t we'll have just (). Moreover, the Functor constraint isn't enough, since we need to interleave it with monadic computations. Therefore, we'll need Traversable:
type MutableLensM m s a b
= forall f . (Traversable f) => (a -> f b) -> (s -> m (f ()))
type MutableLensM' m s a
= MutableLensM m s a a
(Traversable is to monadic computations what Functor is to pure computations).
Again, we create helper functions
mkLensM :: (Monad m) => (s -> m a) -> (s -> b -> m ())
-> MutableLensM m s a b
mkLensM g s f x = g x >>= T.mapM (s x) . f
mget :: (Monad m) => MutableLensM m s a b -> s -> m a
mget l s = liftM getConstant $ l Constant s
mset :: (Monad m) => MutableLensM m s a b -> s -> b -> m ()
mset l s v = liftM runIdentity $ l (const $ Identity v) s
As an example, let's create a mutable lens from a TVar within STM:
alterTVar :: MutableLensM' STM (TVar a) a
alterTVar = mkLensM readTVar writeTVar
These lenses are one-sidedly directly composable with Lens, for example
alterTVar . _1 :: MutableLensM' STM (TVar (a, b)) a
Notes:
Mutable lenses could be made more powerful if we allow that the modifying function to include effects:
type MutableLensM2 m s a b
= (Traversable f) => (a -> m (f b)) -> (s -> m (f ()))
type MutableLensM2' m s a
= MutableLensM2 m s a a
mkLensM2 :: (Monad m) => (s -> m a) -> (s -> b -> m ())
-> MutableLensM2 m s a b
mkLensM2 g s f x = g x >>= f >>= T.mapM (s x)
However, it has two major drawbacks:
It isn't composable with pure Lens.
Since the inner action is arbitrary, it allows you to shoot yourself in the foot by mutating this (or other) lens during the mutating operation itself.
There are other possibilities for monadic lenses. For example, we can create a monadic copy-on-write lens that preserves the original container (just as Lens does), but where the operation involves some monadic action:
type LensCOW m s t a b
= forall f . (Traversable f) => (a -> f b) -> (s -> m (f t))
I've made jLens - a Java library for mutable lenses, but the API is of course far from being as nice as Haskell lenses.
No, you can not constrain the "Functor of the lens" to also be a Monad. The type for a Lens requires that it be compatible with all Functors:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
This reads in English something like: A Lens is a function, which, for all types f where f is a Functor, takes an (a -> f b) and returns an s -> f t. The key part of that is that it must provide such a function for every Functor f, not just some subset of them that happen to be Monads.
Edit:
You could make a Lens (MVar a) (MVar b) a b, since none of s t a, or b are constrained. What would the types on the getter and setter needed to construct it be then? The type of the getter would be (MVar a -> a), which I believe could only be implemented as \_ -> undefined, since there's nothing that extracts the value from an MVar except as IO a. The setter would be (MVar a -> b -> MVar b), which we also can't define since there's nothing that makes an MVar except as IO (MVar b).
This suggests that instead we could instead make the type Lens (MVar a) (IO (MVar b)) (IO a) b. This would be an interesting avenue to pursue further with some actual code and a compiler, which I don't have right now. To combine that with other "purely functional" lenses, we'd probably want some sort of lift to lift the lens into a monad, something like liftLM :: (Monad m) => Lens s t a b -> Lens s (m t) (m a) b.
Code that compiles (2nd edit):
In order to be able to use the Lens s t a b as a Getter s a we must have s ~ t and a ~ b. This limits our type of useful lenses lifted over some Monad to the widest type for s and t and the widest type for a and b. If we substitute b ~ a into out possible type we would have Lens (MVar a) (IO (MVar a)) (IO a) a, but we still need MVar a ~ IO (MVar a) and IO a ~ a. We take the wides of each of these types, and choose Lens (IO (MVar a)) (IO (MVar a)) (IO a) (IO a), which Control.Lens.Lens lets us write as Lens' (IO (MVar a)) (IO a). Following this line of reasoning, we can make a complete system for combining "purely functional" lenses with lenses on monadic values. The operation to lift a "purely function" lens, liftLensM, then has the type (Monad m) => Lens' s a -> LensF' m s a, where LensF' f s a ~ Lens' (f s) (f a).
{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
module Main (
main
) where
import Control.Lens
import Control.Concurrent.MVar
main = do
-- Using MVar
putStrLn "Ordinary MVar"
var <- newMVar 1
output var
swapMVar var 2
output var
-- Using mvarLens
putStrLn ""
putStrLn "MVar accessed through a LensF' IO"
value <- (return var) ^. mvarLens
putStrLn $ show value
set mvarLens (return 3) (return var)
output var
-- Debugging lens
putStrLn ""
putStrLn "MVar accessed through a LensF' IO that also debugs"
value <- readM (debug mvarLens) var
putStrLn $ show value
setM (debug mvarLens) 4 var
output var
-- Debugging crazy box lens
putStrLn ""
putStrLn "MVar accessed through a LensF' IO that also debugs through a Box that's been lifted to LensF' IO that also debugs"
value <- readM ((debug mvarLens) . (debug (liftLensM boxLens))) var
putStrLn $ show value
setM ((debug mvarLens) . (debug (liftLensM boxLens))) (Box 5) var
output var
where
output = \v -> (readMVar v) >>= (putStrLn . show)
-- Types to write higher lenses easily
type LensF f s t a b = Lens (f s) (f t) (f a) (f b)
type LensF' f s a = Lens' (f s) (f a)
type GetterF f s a = Getter (f s) (f a)
type SetterF f s t a b = Setter (f s) (f t) (f a) (f b)
-- Lenses for MVars
setMVar :: IO (MVar a) -> IO a -> IO (MVar a)
setMVar ioVar ioValue = do
var <- ioVar
value <- ioValue
swapMVar var value
return var
getMVar :: IO (MVar a) -> IO a
getMVar ioVar = do
var <- ioVar
readMVar var
-- (flip (>>=)) readMVar
mvarLens :: LensF' IO (MVar a) a
mvarLens = lens getMVar setMVar
-- Lift a Lens' to a Lens' on monadic values
liftLensM :: (Monad m) => Lens' s a -> LensF' m s a
liftLensM pureLens = lens getM setM
where
getM mS = do
s <- mS
return (s^.pureLens)
setM mS mValue = do
s <- mS
value <- mValue
return (set pureLens value s)
-- Output when a Lens' is used in IO
debug :: (Show a) => LensF' IO s a -> LensF' IO s a
debug l = lens debugGet debugSet
where
debugGet ioS = do
value <- ioS^.l
putStrLn $ show $ "Getting " ++ (show value)
return value
debugSet ioS ioValue = do
value <- ioValue
putStrLn $ show $ "Setting " ++ (show value)
set l (return value) ioS
-- Easier way to use lenses in a monad (if you don't like writing return for each argument)
readM :: (Monad m) => GetterF m s a -> s -> m a
readM l s = (return s) ^. l
setM :: (Monad m) => SetterF m s t a b -> b -> s -> m t
setM l b s = set l (return b) (return s)
-- Another example lens
newtype Boxed a = Box {
unBox :: a
} deriving Show
boxLens :: Lens' a (Boxed a)
boxLens = lens Box (\_ -> unBox)
This code produces the following output:
Ordinary MVar
1
2
MVar accessed through a LensF' IO
2
3
MVar accessed through a LensF' IO that also debugs
"Getting 3"
3
"Setting 4"
4
MVar accessed through a LensF' IO that also debugs through a Box that's been lifted to LensF' IO that also debugs
"Getting 4"
"Getting Box {unBox = 4}"
Box {unBox = 4}
"Setting Box {unBox = 5}"
"Getting 4"
"Setting 5"
5
There's probably a better way to write liftLensM without resorting to using lens, (^.), set and do notation. Something seems wrong about building lenses by extracting the getter and setter and calling lens on a new getter and setter.
I wasn't able to figure out how to reuse a lens as both a getter and a setter. readM (debug mvarLens) and setM (debug mvarLens) both work just fine, but any construct like 'let debugMVarLens = debug mvarLens' loses either the fact it works as a Getter, the fact it works as a Setter, or the knowledge that Int is an instance of show so it can me used for debug. I'd love to see a better way of writing this part.
I had the same problem. I tried the methods in Petr and Cirdec's answers but never got to the point I wanted to. Started working on the problem, and at the end, I published the references library on hackage with a generalization of lenses.
I followed the idea of the yall library to parameterize the references with monad types. As a result there is an mvar reference in Control.Reference.Predefined. It is an IO reference, so an access to the referenced value is done in an IO action.
There are also other applications of this library, it is not restricted to IO. An additional feature is to add references (so adding _1 and _2 tuple accessors will give a both traversal, that accesses both fields). It can also be used to release resources after accessing them, so it can be used to manipulate files safely.
The usage is like this:
test =
do result <- newEmptyMVar
terminator <- newEmptyMVar
forkIO $ (result ^? mvar) >>= print >> (mvar .= ()) terminator >> return ()
hello <- newMVar (Just "World")
forkIO $ ((mvar & just & _tail & _tail) %~= ('_':) $ hello) >> return ()
forkIO $ ((mvar & just & element 1) .= 'u' $ hello) >> return ()
forkIO $ ((mvar & just) %~= ("Hello" ++) $ hello) >> return ()
x <- runMaybeT $ hello ^? (mvar & just)
mvar .= x $ result
terminator ^? mvar
The operator & combines lenses, ^? is generalized to handle references of any monad, not just a referenced value that may not exist. The %~= operator is an update of a monadic reference with a pure function.
I am looking for a monad transformer that can be used to track the progress of a procedure. To explain how it would be used, consider the following code:
procedure :: ProgressT IO ()
procedure = task "Print some lines" 3 $ do
liftIO $ putStrLn "line1"
step
task "Print a complicated line" 2 $ do
liftIO $ putStr "li"
step
liftIO $ putStrLn "ne2"
step
liftIO $ putStrLn "line3"
-- Wraps an action in a task
task :: Monad m
=> String -- Name of task
-> Int -- Number of steps to complete task
-> ProgressT m a -- Action performing the task
-> ProgressT m a
-- Marks one step of the current task as completed
step :: Monad m => ProgressT m ()
I realize that step has to exist explicitly because of the monadic laws, and that task has to have an explicit step number parameter because of program determinism/the halting problem.
The monad as described above could, as I see it, be implemented in one of two ways:
Via a function that would return the current task name/step index stack, and a continuation in the procedure at the point that it left off. Calling this function repeatedly on the returned continuation would complete the execution of the procedure.
Via a function that took an action describing what to do when a task step has been completed. The procedure would run uncontrollably until it completed, "notifying" the environment about changes via the provided action.
For solution (1), I have looked at Control.Monad.Coroutine with the Yield suspension functor. For solution (2), I don't know of any already available monad transformers that would be useful.
The solution I'm looking for should not have too much performance overhead and allow as much control over the procedure as possible (e.g. not require IO access or something).
Do one of these solutions sound viable, or are there other solutions to this problem somewhere already? Has this problem already been solved with a monad transformer that I've been unable to find?
EDIT: The goal isn't to check whether all the steps have been performed. The goal is to be able to "monitor" the process while it is running, so that one can tell how much of it has been completed.
This is my pessimistic solution to this problem. It uses Coroutines to suspend the computation on each step, which lets the user perform an arbitrary computation to report some progress.
EDIT: The full implementation of this solution can be found here.
Can this solution be improved?
First, how it is used:
-- The procedure that we want to run.
procedure :: ProgressT IO ()
procedure = task "Print some lines" 3 $ do
liftIO $ putStrLn "--> line 1"
step
task "Print a set of lines" 2 $ do
liftIO $ putStrLn "--> line 2.1"
step
liftIO $ putStrLn "--> line 2.2"
step
liftIO $ putStrLn "--> line 3"
main :: IO ()
main = runConsole procedure
-- A "progress reporter" that simply prints the task stack on each step
-- Note that the monad used for reporting, and the monad used in the procedure,
-- can be different.
runConsole :: ProgressT IO a -> IO a
runConsole proc = do
result <- runProgress proc
case result of
-- We stopped at a step:
Left (cont, stack) -> do
print stack -- Print the stack
runConsole cont -- Continue the procedure
-- We are done with the computation:
Right a -> return a
The above program outputs:
--> line 1
[Print some lines (1/3)]
--> line 2.1
[Print a set of lines (1/2),Print some lines (1/3)]
--> line 2.2
[Print a set of lines (2/2),Print some lines (1/3)]
[Print some lines (2/3)]
--> line 3
[Print some lines (3/3)]
The actual implementation (See this for a commented version):
type Progress l = ProgressT l Identity
runProgress :: Progress l a
-> Either (Progress l a, TaskStack l) a
runProgress = runIdentity . runProgressT
newtype ProgressT l m a =
ProgressT
{
procedure ::
Coroutine
(Yield (TaskStack l))
(StateT (TaskStack l) m) a
}
instance MonadTrans (ProgressT l) where
lift = ProgressT . lift . lift
instance Monad m => Monad (ProgressT l m) where
return = ProgressT . return
p >>= f = ProgressT (procedure p >>= procedure . f)
instance MonadIO m => MonadIO (ProgressT l m) where
liftIO = lift . liftIO
runProgressT :: Monad m
=> ProgressT l m a
-> m (Either (ProgressT l m a, TaskStack l) a)
runProgressT action = do
result <- evalStateT (resume . procedure $ action) []
return $ case result of
Left (Yield stack cont) -> Left (ProgressT cont, stack)
Right a -> Right a
type TaskStack l = [Task l]
data Task l =
Task
{ taskLabel :: l
, taskTotalSteps :: Word
, taskStep :: Word
} deriving (Show, Eq)
task :: Monad m
=> l
-> Word
-> ProgressT l m a
-> ProgressT l m a
task label steps action = ProgressT $ do
-- Add the task to the task stack
lift . modify $ pushTask newTask
-- Perform the procedure for the task
result <- procedure action
-- Insert an implicit step at the end of the task
procedure step
-- The task is completed, and is removed
lift . modify $ popTask
return result
where
newTask = Task label steps 0
pushTask = (:)
popTask = tail
step :: Monad m => ProgressT l m ()
step = ProgressT $ do
(current : tasks) <- lift get
let currentStep = taskStep current
nextStep = currentStep + 1
updatedTask = current { taskStep = nextStep }
updatedTasks = updatedTask : tasks
when (currentStep > taskTotalSteps current) $
fail "The task has already completed"
yield updatedTasks
lift . put $ updatedTasks
The most obvious way to do this is with StateT.
import Control.Monad.State
type ProgressT m a = StateT Int m a
step :: Monad m => ProgressT m ()
step = modify (subtract 1)
I'm not sure what you want the semantics of task to be, however...
edit to show how you'd do this with IO
step :: (Monad m, MonadIO m) => ProgressT m ()
step = do
modify (subtract 1)
s <- get
liftIO $ putStrLn $ "steps remaining: " ++ show s
Note that you'll need the MonadIO constraint to print the state. You can have a different sort of constraint if you need a different effect with the state (i.e. throw an exception if the number of steps goes below zero, or whatever).
Not sure if this is exactly what you want, but here is an implementation that enforces the correct number of steps and requires there to be zero steps left at the end. For simplicity, I'm using a monad instead of a monad transformer over IO. Note that I am not using the Prelude monad to do what I'm doing.
UPDATE:
Now can extract the number of remaining steps. Run the following with -XRebindableSyntax
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
module Test where
import Prelude hiding (Monad(..))
import qualified Prelude as Old (Monad(..))
-----------------------------------------------------------
data Z = Z
data S n = S
type Zero = Z
type One = S Zero
type Two = S One
type Three = S Two
type Four = S Three
-----------------------------------------------------------
class Peano n where
peano :: n
fromPeano :: n -> Integer
instance Peano Z where
peano = Z
fromPeano Z = 0
instance Peano (S Z) where
peano = S
fromPeano S = 1
instance Peano (S n) => Peano (S (S n)) where
peano = S
fromPeano s = n `seq` (n + 1)
where
prev :: S (S n) -> (S n)
prev S = S
n = fromPeano $ prev s
-----------------------------------------------------------
class (Peano s, Peano p) => Succ s p | s -> p where
instance Succ (S Z) Z where
instance Succ (S n) n => Succ (S (S n)) (S n) where
-----------------------------------------------------------
infixl 1 >>=, >>
class ParameterisedMonad m where
return :: a -> m s s a
(>>=) :: m s1 s2 t -> (t -> m s2 s3 a) -> m s1 s3 a
fail :: String -> m s1 s2 a
fail = error
(>>) :: ParameterisedMonad m => m s1 s2 t -> m s2 s3 a -> m s1 s3 a
x >> f = x >>= \_ -> f
-----------------------------------------------------------
newtype PIO p q a = PIO { runPIO :: IO a }
instance ParameterisedMonad PIO where
return = PIO . Old.return
PIO io >>= f = PIO $ (Old.>>=) io $ runPIO . f
-----------------------------------------------------------
data Progress p n a = Progress a
instance ParameterisedMonad Progress where
return = Progress
Progress x >>= f = let Progress y = f x in Progress y
runProgress :: Peano n => n -> Progress n Zero a -> a
runProgress _ (Progress x) = x
runProgress' :: Progress p Zero a -> a
runProgress' (Progress x) = x
task :: Peano n => n -> Progress n n ()
task _ = return ()
task' :: Peano n => Progress n n ()
task' = task peano
step :: Succ s n => Progress s n ()
step = Progress ()
stepsLeft :: Peano s2 => Progress s1 s2 a -> (a -> Integer -> Progress s2 s3 b) -> Progress s1 s3 b
stepsLeft prog f = prog >>= flip f (fromPeano $ getPeano prog)
where
getPeano :: Peano n => Progress s n a -> n
getPeano prog = peano
procedure1 :: Progress Three Zero String
procedure1 = do
task'
step
task (peano :: Two) -- any other Peano is a type error
--step -- uncommenting this is a type error
step -- commenting this is a type error
step
return "hello"
procedure2 :: (Succ two one, Succ one zero) => Progress two zero Integer
procedure2 = do
task'
step `stepsLeft` \_ n -> do
step
return n
main :: IO ()
main = runPIO $ do
PIO $ putStrLn $ runProgress' procedure1
PIO $ print $ runProgress (peano :: Four) $ do
n <- procedure2
n' <- procedure2
return (n, n')