UserPreferences

MonadState


The following describes Control.Monad.State from the hierarchical libraries (and specifically, from GHC).

Control.Monad.State

Description

The state monad hides state from us (if it needs to be passed as an extra parameter). This is useful when you have a few variables that need to be "updated." Common uses for State monads are unique name supplies and counters. If you just don't want to have to pass around a variable, but don't really intend to change it (or the changes are temporary) then MonadReader would likely be a better choice. MonadState is not used for references or updateable arrays; instead use the ST Monad or the IO Monad.

There is also a transformer version, StateT.

Details

(see the hierarchical libs documentation below in References)

Possible Implementation

Note: this implementation requires ?MultiParameterTypeClasses and FunDeps which are not Haskell98

newtype State s a = State { runState ::  (s -> (a,s)) }

instance Monad (State s) where
    return a = State $ \s -> (a,s)
    x >>= f = State $ \s -> let (v,s') = runState x s in runState (f v) s'

class MonadState m s | m -> s where
    get :: m s
    put :: s -> m ()

instance MonadState (State s) s where
    get = State $ \s -> (s,s)
    put s = State $ \_ -> ((),s)

gets :: (MonadState m s) => (s -> a) -> m a
gets f = f `liftM` get

modify :: (MonadState m s) => (s -> s) -> m ()
modify f = get >>= put . f

Examples

if we were to transform a tree so that each of the leaves were numbered

data Tree a = Leaf a | Branch (Tree a) (Tree a)
we could either write
number :: Int -> Tree a -> (Tree (a,Int) , Int)
number seed (Leaf a) = (Leaf (a,seed),seed + 1)
number seed (Branch left right)
 = let (left',lseed) = number seed left
       (right',rseed) = number lseed right
   in
       (Branch left' right' rseed)
or we could encapsulate the whole shebang in a state monad
numberST :: Tree a -> State Int (Tree (a,Int))
numberST (Leaf a) = do
                        next <- get
                        put (next + 1)
                        return Leaf (a,next)

numberST (Branch l r) = do
                           left <- numberST l
                           right <- numberST r
                           return (Branch left right)
-- ChrisAngus

A function to increment a counter. Taken from the paper Generalising Monads to Arrows, John Hughes (http://www.math.chalmers.se/~rjmh/), November 1998.

tick :: State Int Int
tick = do n <- get
          put (n+1)
          return n
Add one to the given number using the state monad.
plusOne :: Int -> Int
plusOne n = execState tick n
A contrived addition example. Works only with positive numbers.
plus :: Int -> Int -> Int
plus n x = execState (sequence $ replicate n tick) x

An example from The Craft of Functional Programming, Simon Thompson (http://www.cs.ukc.ac.uk/people/staff/sjt/), Addison-Wesley 1999: \"Given an arbitrary tree, transform it to a tree of integers in which the original elements are replaced by natural numbers, starting from 0. The same element has to be replaced by the same number at every occurrence, and when we meet an as-yet-unvisited element we have to find a 'new' number to match it with."

data Tree a = Nil | Node a (Tree a) (Tree a) deriving (Show, Eq)
type Table a = [a]
testTree = Node "Zero" (Node "One" (Node "Two" Nil Nil) (Node "One" (Node "Zero" Nil Nil) Nil)) Nil

numTree :: (Eq a) => Tree a -> Tree Int
numTree t = evalState (numberTree t) []

numberTree :: Eq a => Tree a -> State (Table a) (Tree Int)
numberTree Nil = return Nil
numberTree (Node x t1 t2)
    =  do num <- numberNode x
          nt1 <- numberTree t1
          nt2 <- numberTree t2
          return (Node num nt1 nt2)
  where
    numberNode :: Eq a => a -> State (Table a) Int
    numberNode x
        = do table <- get
             (newTable, newPos) <- return (nNode x table)
             put newTable
             return newPos
    nNode :: (Eq a) => a -> Table a -> (Table a, Int)
    nNode x table
        = case (elemIndex x table) of
          Nothing -> (table ++ [x], length table)
          Just i  -> (table, i)

So for example:

numTree testTree => Node 0 (Node 1 (Node 2 Nil Nil) (Node 1 (Node 0 Nil Nil) Nil)) Nil

There is also a construct in Control.Monad.State for encapsulating one monad inside a State monad; it's called StateT. In this example by MarkCarroll, the IO state is nested inside a state monad that carries information about our computation:

module NestedMonad where

import Control.Monad.State
import Data.List

get_length :: String -> IO Int

get_length name =
    do contents <- readFile name
       return (length (lines contents))

update_best_with :: MonadState (String, Int) m => (String, Int) -> m ()

update_best_with (current_name, current_count) =
    do (best_name, best_count) <- get
       if current_count > best_count
          then put (current_name, current_count)
          else return ()

do_next :: String -> StateT (String, Int) IO ()

do_next name =
    do count <- lift $ get_length name
       update_best_with (name, count)

longest_file :: [String] -> IO (String, Int)

longest_file names =
    execStateT (sequence_ (map do_next names)) ("none", 0)

main = do (name, count) <- longest_file ["/etc/hostname", "/etc/ntp.conf", "/etc/timezone"]
          putStrLn ("Longest file is " ++ name ++ " which is " ++ show count ++ " lines long")

References

The base libraries for GHC provide such a construct, see the [WWW]documentation for Control.Monad.State.

Notes

Note: Perhaps this can be added to the StateT documentation? Does anyone have a better example? Is there a better way to describe the standardness of the Control.Monad.State module?

-- IsaacJones


Using ReaderT in place of StateT IO

One way to simulate global variables is by using StateT on top of IO, and place the runStateT in "main" to carry the variables in a record. This approach can be made even nicer by adding a few types and accessors for external module, like this:

import Control.Monad.State

data Vars = Vars {
   var1 :: Int,
   var2 :: Float
}

type MyState a = StateT Vars IO a
type Selector a = (MyState a, a -> MyState ())

s1 :: Selector Int
s1 = (gets var1, \x -> modify (\vs -> vs {var1 = x})

s2 :: Selector Float
s2 = (gets var2, \x -> modify (\vs -> vs {var2 = x})

sel :: Selector a -> MyState a
sel = fst

mods :: Selector a -> (a -> a) -> MyState ()
mods (gf,uf) mfun = do st <- gf
                       uf (mfun st)

sample :: MyState ()
sample = do a <- sel s1
            mods s2 (\x -> x * (fromIntegral a))
            b <- sel s2
            liftIO $ print b

main = runStateT sample (Vars 2 1.3)

However, it is often easier (and faster) to replace this with a ReaderT with IORef in the record fields:

import Control.Monad.Reader
import Data.IORef

data Vars = Vars {
    var1 :: IORef Int,
    var2 :: IORef Float
}

type MyState a = ReaderT Vars IO a
type Selector a = Vars -> IORef a

sel :: Selector a -> MyState a
sel s = do hs <- ask
           liftIO $ readIORef (s hs)

mods :: Selector a -> (a -> a) -> MyState ()
mods sel mod = do hs <- ask
                  liftIO $ modifyIORef (sel hs) mod

sample :: MyState ()
sample = do a <- sel var1
            mods var2 (\x -> x * (fromIntegral a))
            b <- sel var2
            liftIO $ print b

main = do r1 <- newIORef 2
          r2 <- newIORef 1.3
          runReaderT sample (Vars r1 r2)


CategoryMonad