packages feed

lambdabot-4.1: scripts/FT/FreeTheorems/TheoremData.hs

-- Copyright 2006, Sascha Boehme.




-- | This module provides a state object used in various stages of the theorem
--   generation process. It serves to create unique indices.

module FreeTheorems.TheoremData (
    TheoremData,
    TheoremState,
    newTheoremData,
    execute,
    executeWith,
    newRelationVariable,
    newVariablesFor,
    newRelationAsFunctionVariable
) where



import FreeTheorems.Declarations (isDefined)
import FreeTheorems.Types
import Control.Monad (liftM2)
import Control.Monad.State (State, get, modify, runState)



-- | A type synonym for the state used when modifying 'TheoremData'.

type TheoremState a = State TheoremData a



-- | Stores information used to create unique indices. It is used while
--   generating theorems for types.

data TheoremData = TheoremData {
                    forbiddenVariable :: TermVariable,
                        -- ^ The name of the type, from which the theorem is
                        --   generated. Used to avoid name clashes.

                    nextRelVarIndex :: Int,
                        -- ^ The next index when creating a new relation
                        --   variable.

                    nextTypeTermVarIndex :: Int,
                        -- ^ The next index when creating a new type term
                        --   variable.

                    nextTermVarIndex  :: Int,
                        -- ^ Next index when creating a new term variable.

                    nextFunVarIndex   :: Int,
                        -- ^ Next index when creating a new term variable
                        --   representing a function.

                    nextRelFunVarIndex   :: Int
                        -- ^ Next index when creating a new term variable
                        --   representing a function specialized from a
                        --   relation.
                  }



-- | Creates new theorem data based on the name of the type from which the
--   theorem is generated and the relation variable mapping of 'applyDelta'.

newTheoremData :: TermVariable -> TheoremData
newTheoremData tv = TheoremData {
                      forbiddenVariable = tv,
                      nextRelVarIndex = 1,
                      nextTypeTermVarIndex = 1,
                      nextTermVarIndex = 1,
                      nextFunVarIndex = 1,
                      nextRelFunVarIndex = 1
                    }



-- | Executes a 'TheoremState' action and returns the result of it along with
--   the last data. The latter may be used to execute consecutive actions.

execute :: TermVariable -> TheoremState a -> (a, TheoremData)
execute tv action = executeWith (newTheoremData tv) action


-- | Executes a 'TheoremState' action using previously generated data. Returns
--   the action's result and updated data.

executeWith :: TheoremData -> TheoremState a -> (a, TheoremData)
executeWith tdata action = runState action tdata



-- | Creates a new relation variable.

newRelationVariable :: TypeVariable -> TheoremState RelationVariable
newRelationVariable v = do
  ttv1 <- newTypeTermVariable
  ttv2 <- newTypeTermVariable

  tdata <- get
  let index  = nextRelVarIndex tdata
  let rv = R index v (ttv1, ttv2)
  modify (\tdata -> tdata { nextRelVarIndex = index + 1 })
  return rv



-- | Creates a new type term variable.

newTypeTermVariable :: TheoremState TypeTermVariable
newTypeTermVariable = do
  tdata <- get
  let index = nextTypeTermVarIndex tdata
  modify (\tdata -> tdata { nextTypeTermVarIndex = index + 1 })

  -- check if the name of the new type term variable collides with an already
  -- existing type constructor name
  if isDefined ("T" ++ show index)
    then newTypeTermVariable
    else return (T index)



-- Generates a term variable for a non-function term or generates a function
-- variable for a function, even if it is hidden by abstractions.

newVariablesFor :: Relation -> TheoremState (TermVariable, TermVariable)
newVariablesFor rel =
  case rel of
    RelFun _ _ _    -> newFunctionVariables
    RelForall _ _ r -> newVariablesFor r
    otherwise       -> newTermVariables



-- | Creates a new pair of term variables (@x_i@ and @y_i@).
--   The created variables are checked against the name of the type from which
--   the theorem is generated to ensure that the variables are unique.

newTermVariables :: TheoremState (TermVariable, TermVariable)
newTermVariables = do
  tdata <- get
  let index = nextTermVarIndex tdata
  modify (\tdata -> tdata { nextTermVarIndex = index + 1 })
  let x = (TV "x" index)
  let y = (TV "y" index)
  areInUse <- liftM2 (||) (isAlreadyInUse x) (isAlreadyInUse y)
  if areInUse
    then newTermVariables
    else return (x, y)



-- | Creates a new pair of function term variables (@f_i@ and @g_i@).
--   The created variables are checked against the name of the type from which
--   the theorem is generated to ensure that the variables are unique.

newFunctionVariables :: TheoremState (TermVariable, TermVariable)
newFunctionVariables = do
  tdata <- get
  let index = nextFunVarIndex tdata
  modify (\tdata -> tdata { nextFunVarIndex = index + 1 })
  let f = (TV "f" index)
  let g = (TV "g" index)
  areInUse <- liftM2 (&&) (isAlreadyInUse f) (isAlreadyInUse g)
  if areInUse
    then newFunctionVariables
    else return (f, g)



-- | Creates a new function variable @h_i@ which is used to replace or
--   specialize a relation variable.
--   The created variable is checked against the name of the type from which
--   the theorem is generated to ensure that the variable is unique.

newRelationAsFunctionVariable :: TheoremState TermVariable
newRelationAsFunctionVariable = do
  tdata <- get
  let index = nextRelFunVarIndex tdata
  modify (\tdata -> tdata { nextRelFunVarIndex = index + 1 })
  let h = TV "h" index
  isInUse <- isAlreadyInUse h
  if isInUse
    then newRelationAsFunctionVariable
    else return h



-- | Checks if a generated variable is unique. Returns 'True' if the same name
--   is already in use.

isAlreadyInUse :: TermVariable -> TheoremState Bool
isAlreadyInUse var = do
  tdata <- get
  return (var == forbiddenVariable tdata)