summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpb <pb@9f8f72e9-4bf4-416e-b76e-7d4203597157>2010-03-28 21:42:11 +0000
committerpb <pb@9f8f72e9-4bf4-416e-b76e-7d4203597157>2010-03-28 21:42:11 +0000
commit8bef12cb86af79420e61ce8cd60cfb7ae1e69953 (patch)
tree4300c34a6e691821172b26f7a3220647c8af1a54
parent2341aa600daac2c8afa366cd612a893580104a93 (diff)
git-svn-id: https://ssl.buetow.org/repos/hsbot/trunk@56 9f8f72e9-4bf4-416e-b76e-7d4203597157
-rw-r--r--examples/example15.hs81
1 files changed, 81 insertions, 0 deletions
diff --git a/examples/example15.hs b/examples/example15.hs
new file mode 100644
index 0000000..945f9a8
--- /dev/null
+++ b/examples/example15.hs
@@ -0,0 +1,81 @@
+{- Author: Jeff Newbern
+ Maintainer: Jeff Newbern <jnewbern@nomaware.com>
+ Time-stamp: <Thu Jul 24 13:39:30 2003>
+ License: GPL
+-}
+
+{- DESCRIPTION
+
+Example 15 - Using the State monad
+
+Usage: Compile the code and execute the command.
+ It will print two identical random values of type MyType.
+ The first value is computed without the State monad and
+ the second is computed using the State monad.
+ The MyType values are random but obey some internal
+ invariants:
+ o the Int value is in the range 1-100.
+ o the Char value is in the range 'a'-'z'
+ o the absolute value of the second Int value is
+ less than or equal to the value of the first Int value
+
+Try: ./ex15
+-}
+
+import Monad
+import System
+import IO
+import Random
+import Control.Monad.State
+
+-- This is the type that we want to generate random values of
+data MyType = MT Int Bool Char Int deriving Show
+
+{- Without using the State monad, we would have to thread the
+ random number generator state by hand. The function would
+ look like this:
+-}
+makeRandomValue :: StdGen -> (MyType, StdGen)
+makeRandomValue g = let (n,g1) = randomR (1,100) g
+ (b,g2) = random g1
+ (c,g3) = randomR ('a','z') g2
+ (m,g4) = randomR (-n,n) g3
+ in (MT n b c m, g4)
+
+{- Using the State monad, we can define a function that returns
+ a random value and updates the random generator state at
+ the same time.
+-}
+
+getAny :: (Random a) => State StdGen a
+getAny = do g <- get
+ (x,g') <- return $ random g
+ put g'
+ return x
+
+-- similar to getAny, but it bounds the random value returned
+getOne :: (Random a) => (a,a) -> State StdGen a
+getOne bounds = do g <- get
+ (x,g') <- return $ randomR bounds g
+ put g'
+ return x
+
+{- Using the State monad with StdGen as the state, we can build
+ random complex types without manually threading the
+ random generator states through the code.
+-}
+makeRandomValueST :: StdGen -> (MyType, StdGen)
+makeRandomValueST = runState (do n <- getOne (1,100)
+ b <- getAny
+ c <- getOne ('a','z')
+ m <- getOne (-n,n)
+ return (MT n b c m))
+
+-- print a random value of MyType, showing the two implementations
+-- are equivalent
+main :: IO ()
+main = do g <- getStdGen
+ print $ fst $ makeRandomValue g
+ print $ fst $ makeRandomValueST g
+
+-- END OF FILE