Personal tools

Simple StateT use

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(+cat)
 
(2 intermediate revisions by 2 users not shown)
Line 32: Line 32:
 
io :: IO a -> StateT [Integer] IO a
 
io :: IO a -> StateT [Integer] IO a
 
io = liftIO
 
io = liftIO
 +
 +
--
 +
-- another example: a guessing game
 +
-- (from http://scsibug.com/2006/11/28/a-simple-game-with-statet/)
 +
--
 +
 +
module Main where
 +
import System.Random
 +
import Control.Monad.State
 +
 +
main = do answer <- getStdRandom (randomR (1,100)) -- think of a number
 +
          putStrLn "I'm thinking of a number between 1 and 100, can you guess it?"
 +
          guesses <- execStateT (guessSession answer) 0
 +
          putStrLn $ "Success in " ++ (show guesses) ++ " tries."
 +
 +
guessSession :: Int -> StateT Int IO ()
 +
guessSession answer =
 +
    do gs <- lift getLine    -- get guess from user
 +
      let g = read gs      -- convert to number
 +
      modify (+1)          -- increment number of guesses
 +
      case compare g answer of
 +
              LT -> do lift $ putStrLn "Too low"
 +
                      guessSession answer
 +
              GT -> do lift $ putStrLn "Too high"
 +
                      guessSession answer
 +
              EQ -> lift $ putStrLn "Got it!"
 +
 +
 +
--
 +
-- another example: a global state
 +
-- (corrected from http://www.haskell.org/hawiki/MonadState?action=show)
 +
--
 +
 +
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)
 +
 
</haskell>
 
</haskell>
  
 
[[Category:Code]]
 
[[Category:Code]]
 
[[Category:Monad]]
 
[[Category:Monad]]

Latest revision as of 17:16, 14 May 2007

A small example showing how to combine a State monad (in this case a unique supply), with the IO monad, via a monad transformer.

No need to resort to nasty mutable variables or globals!

import Control.Monad.State
 
main :: IO ()
main = runStateT code [1..] >> return ()
--
-- layer an infinite list of uniques over the IO monad
--
 
code :: StateT [Integer] IO ()
code = do
    x <- pop
    io $ print x
    y <- pop
    io $ print y
    return ()
 
--
-- pop the next unique off the stack
--
pop :: StateT [Integer] IO Integer
pop = do
    (x:xs) <- get
    put xs
    return x
 
io :: IO a -> StateT [Integer] IO a
io = liftIO
 
--
-- another example: a guessing game 
-- (from http://scsibug.com/2006/11/28/a-simple-game-with-statet/)
--
 
module Main where
import System.Random
import Control.Monad.State
 
main = do answer <- getStdRandom (randomR (1,100)) -- think of a number
          putStrLn "I'm thinking of a number between 1 and 100, can you guess it?"
          guesses <- execStateT (guessSession answer) 0
          putStrLn $ "Success in " ++ (show guesses) ++ " tries."
 
guessSession :: Int -> StateT Int IO ()
guessSession answer =
    do gs <- lift getLine    -- get guess from user
       let g = read gs       -- convert to number
       modify (+1)           -- increment number of guesses
       case compare g answer of
              LT -> do lift $ putStrLn "Too low"
                       guessSession answer
              GT -> do lift $ putStrLn "Too high"
                       guessSession answer
              EQ -> lift $ putStrLn "Got it!"
 
 
--
-- another example: a global state 
-- (corrected from http://www.haskell.org/hawiki/MonadState?action=show)
--
 
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)