I need a global counter, starting from 0, 1, 2, 3, ..... I kind of understand that this "impure" code should be separately implemented... I am just starting to understand Monad, but have no idea how to implement this global counter using Monad? This could be very useful example for understanding if it is possible
-
1As Ankur has said this is basically a State monad. The implementation of the Monad instance - `return` and bind `(>>=)` - would be the same as State, however you would want a less general update operation than the State monad's `put` (`put` can change the state in arbitrary ways). I'd suggest a good interface would be `next` which increases the count and returns the new count. Retaining a `get` operation that just queries the count without updating it would be good too. – stephen tetley Jun 10 '11 at 07:49
-
6Check out [the supply monad](http://www.haskell.org/haskellwiki/New_monads/MonadSupply). To get a counter with it, just use `[0..]` as the supply. – hammar Jun 10 '11 at 10:44
-
1@hammar Your comment should be an answer, and it should be accepted. – Tom Crockett Sep 13 '11 at 03:34
4 Answers
State monad gives you state but only inside the monad. It is not persistent across repeated invocations of the function.
If you want truly global, mutable state you might want to do something like:
import Data.IORef
type Counter = Int -> IO Int
makeCounter :: IO Counter
makeCounter = do
r <- newIORef 0
return (\i -> do modifyIORef r (+i)
readIORef r)
testCounter :: Counter -> IO ()
testCounter counter = do
b <- counter 1
c <- counter 1
d <- counter 1
print [b,c,d]
main = do
counter <- makeCounter
testCounter counter
testCounter counter
Here makeCounter
creates a global, mutable variable that is keeps its state across invocations and destroys purity. For example, in the main function two identical calls to testCounter
gives different results.
> main
[1,2,3]
[4,5,6]
-
1Why did you make the signature of `Counter` `Int -> IO Int` instead of simply `IO Int`? – Michael Snoyman Sep 13 '11 at 07:47
You can implement this using a State
monad, which stores the current value of your counter as the state. You can then use get
to get the current counter value, and modify (+1)
to increment it.
One useful variation of this is the Supply
monad, where you can use an arbitrary sequence as your "counter", so to have a plain counter starting from zero, just use [0..]
as the supply.

- 138,522
- 17
- 304
- 385
What you can look into is state monad. This is a general purpose monad which can be used to manage state. In your case the counter is just a state that you want to maintain.

- 33,367
- 2
- 46
- 72
While State is fine, you don't need to inspect the counter while calculating, but just to increase it, so the Writer monad should be sufficient. See Learn you a Haskell for a (not too serious) introduction.

- 54,104
- 13
- 100
- 195
-
I'm not sure using a Writer would be sufficient - if you want to know the current count during a computation you can't get it from Writer (write only state) it has to be a State monad. – stephen tetley Jun 10 '11 at 07:38
-
2@stephen tetley The question doesn't make clear if you need the counter value during the calculation. However, if you need just the end result of the counter, a `Writer` is "safer" and easier to use. – Landei Jun 10 '11 at 08:47