File: Example.hs

package info (click to toggle)
haskell-multistate 0.8.0.4-3
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 280 kB
  • sloc: haskell: 3,162; makefile: 6
file content (122 lines) | stat: -rw-r--r-- 3,534 bytes parent folder | download | duplicates (3)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}

module Main where



import Control.Monad.Trans.MultiState

import Control.Applicative ( (<$>), (<*>) )

import Control.Monad.Trans ( lift )
import Control.Monad.Writer



{-
Small example showing
  1) a MultiState containing a Char and a String,
  2) the polymorphic mGet,
  3) how to initially put values into the MultiState using withMultiState,
  4) the type inference at work - note that there was no need to annotate
     combinedPrint
-}

simpleExample :: IO ()
simpleExample = runMultiStateTNil_
              $ withMultiState 'H'              -- add a Char to the state
              $ withMultiState "ello, World!" -- add a String to the state
              $ do
  -- the monad here is MultiStateT '[String, Char] IO
  let combinedPrint = do
        c  <- mGet
        cs <- mGet
        -- i <- mGet -- No instance for (Control.Monad.MultiState.ContainsType Int '[])
        -- lift $ print $ (i :: Int)
        lift $ putStrLn (c:cs)
  combinedPrint
  mSet 'J' -- we set the Char in the state to 'J'
  combinedPrint

-- output:
--  "Hello, World!
--   Jello, World!
--  "

-- and a more complex example:

newtype Account = Account Float
newtype Interest = Interest Float

setAccount :: MonadMultiState Account m => Float -> m ()
setAccount x = mSet (Account x)
getAccount :: MonadMultiState Account m => m Float
getAccount = do
  (Account x) <- mGet
  return x
modAccount :: MonadMultiState Account m => (Float -> Float) -> m ()
modAccount f = do
  (Account x) <- mGet
  mSet (Account (f x))

-- wait for a specific time, changing the account according to interest
wait :: ( MonadMultiState Account m
        , MonadMultiState Interest m )
     => Float
     -> m ()
wait t = do
  (Interest i) <- mGet
  (Account x) <- mGet
  mSet (Account (x*(1+i)**t))

logAccount :: ( MonadWriter [String] m
              , MonadMultiState Account m)
           => m ()
logAccount = do
  (Account x) <- mGet
  tell $ ["account balance = " ++ show x]

accountCalculation :: Writer [String] ()
accountCalculation = runMultiStateTNil_ $ do
  tell ["account calculation start"]
  -- we cannot use any of the account methods here, because state is empty
  -- logAccount
  --   -->
  --   No instance for (Control.Monad.MultiState.ContainsType Account '[])
  withMultiState (Account 0.0) $ do -- state contains an Account.
    logAccount
    modAccount (+10.0)
    logAccount
    -- trying to use "wait" here would give type error, like above.
    withMultiState (Interest 0.03) $ do -- state now also contains Interest.
      wait 10.0 -- we can use wait, because state contains all
                -- necessary stuff.
      logAccount
      modAccount (\x -> x - 10.0)
      wait 10.0
      logAccount
      mSet (Interest 0.00)
      wait 10.0
    -- we can return back to the environment without interest
    -- but the changes to the account are still present
    logAccount
  -- and we can return to an empty state
  tell ["account calculation end"]

main = do
  simpleExample
  mapM_ putStrLn $ execWriter accountCalculation


-- whatIsNotPossible :: MultiStateT '[String] IO ()
-- whatIsNotPossible = mGet >>= (lift . print) -- type ambiguous

-- another thing that is not directly possible is the restriction to
-- specific values, i.e. a function
--  restrict :: MultiStateT xvalues m a -> MultiStateT yvalues m a
-- where yvalues is a "superset" of xvalues.

--TODO: example with mGetRaw and withMultiStates