module Gensym (
    Gensym(..), gensym, runGensym
  ) where

import Control.Applicative

-- Gensym monad

data Gensym a = G (Int -> (Int, a))

instance Monad Gensym where
    return v = G(\x -> (x,v))
    m >>= k = G(\x -> let G f = m in
                      let (x', v) = f x in 
                      let G f' = k v in f' x')

instance Functor Gensym where
    fmap f x = x >>= (return . f)

instance Control.Applicative.Applicative Gensym where
    pure = return
    f <*> x = do f' <- f ; x' <- x ; return (f' x')

gensym :: Gensym Int
gensym = G(\x -> (x+1, x))

runGensym (G f) = snd $ f 0

instance Show a => Show (Gensym a) where
    show x = show $ runGensym x