# Writing a counter function

Andrew J Bromage andrew@bromage.org
Mon, 1 Jul 2002 14:29:35 +1000

```G'day all.

On Sun, Jun 30, 2002 at 01:51:56PM +0100, Peter G. Hancock wrote:

> Why not have a monad m a = Int -> (a,Int) which is a state monad plus
> the operation bump : Int -> m Int
>
>  bump k n = (n,n+k)

Oh, ye of insufficient genericity.  We can do better than that...

class (Monad m, Enum i) => MonadCounter i m | m -> i where
bump :: Int -> m i

newtype CounterT i m a = CounterT { runCounterT :: i -> m (a,i) }

return a = CounterT \$ \x -> return (a, x)
m >>= k  = CounterT \$ \x -> do
(a, x') <- runCounterT m x
runCounterT (k a) x'
fail str = CounterT \$ \_ -> fail str

instance (Monad m, Enum i) => MonadCounter i (CounterT i m) where
bump k = CounterT \$ \x ->
let (next:_) = drop k [x..]
in return (x, next)

instance (Enum i) => MonadTrans (CounterT i) where
lift m = CounterT \$ \x -> do
a <- m
return (a, x)

evalCounterT :: (Monad m, Enum i) => CounterT i m a -> i -> m a
evalCounterT m x = do
(a, _) <- runCounterT m x
return a

-- Example code follows

main :: IO ()
main = evalCounterT count 0

count :: CounterT Int IO ()
count = do
x1 <- bump 1
x2 <- bump 5
x3 <- bump 0
x4 <- bump 1
lift (putStrLn \$ show [x1,x2,x3,x4])

I'd better get back to work now.

Cheers,
Andrew Bromage

```