module Nominal.Atoms.Space where

import Control.Monad (replicateM)
import Control.Monad.State (State, evalState, state)
import Nominal.Atoms (Atom, atom)

----------------------------------------------------------------------------------------------------
-- Atoms space
----------------------------------------------------------------------------------------------------

-- | Space with free atoms names.
type AtomsSpace = State [String]

allAtomsNames :: [String]
allAtomsNames = [1..] >>= (`replicateM` ['a'..'z'])

atomsSpace :: (String -> a) -> AtomsSpace a
atomsSpace f = state (\s -> (f $ head s, tail s))

-- | Creates a new atom with a previously unused name.
newAtom :: AtomsSpace Atom
newAtom  = atomsSpace atom

-- | Evaluates given value having 'newAtom' commands.
runNLambda :: AtomsSpace a -> a
runNLambda nl = evalState nl allAtomsNames