{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -Wall #-}

-- {-# OPTIONS_GHC -fno-warn-unused-imports #-} -- TEMP
-- {-# OPTIONS_GHC -fno-warn-unused-binds   #-} -- TEMP

----------------------------------------------------------------------
-- |
-- Module      :  Language.NameSupply
-- Copyright   :  (c) 2012 Tabula, Inc.
-- 
-- Maintainer  :  conal@tabula.com
-- Stability   :  experimental
-- 
-- Supply monad
----------------------------------------------------------------------

module Language.NameSupply
  ( Supply,supplyNew,allNames,Name,NameM,withNames,withAllNames
  ) where

-- TODO: explicit exports

import Data.Functor ((<$>))
import Control.Monad.Trans.State

type Supply x = State [x]

-- | Generate a new variable name
supplyNew :: Supply x x
supplyNew = do x:xs' <- get
               put xs'
               return x

type Name = String

-- | All names made purely of lower-case alphabetic characters, ordered by
-- increasing size (starting with one) and alphabetically within each size.
allNames :: [Name]
allNames = reverse <$> tail ns
 where
   ns = "" : [c : n | n <- ns, c <- ['a'..'z']]

-- allNames = reverse <$> tail ns
--  where
--    ns = "" : liftA2 (flip (:)) ns ['a'..'z']

type NameM = Supply Name

withNames :: [Name] -> NameM a -> a
withNames = flip evalState

withAllNames :: NameM a -> a
withAllNames = withNames allNames