haskhol-core-1.0.0: src/HaskHOL/Core/State.hs
{-# LANGUAGE DeriveDataTypeable, TemplateHaskell, ViewPatterns #-}
{-|
Module: HaskHOL.Core.State
Copyright: (c) The University of Kansas 2013
LICENSE: BSD3
Maintainer: ecaustin@ittc.ku.edu
Stability: unstable
Portability: unknown
This module exports the stateful layer of HaskHOL. It consists of:
* Stateful type primitives not found in "HaskHOL.Core.Types".
* Stateful term primitives not found in "HaskHOL.Core.Terms".
* Stateful theory extension primitives not found in "HaskHOL.Core.Kernel".
* A very primitive debugging system.
-}
module HaskHOL.Core.State
( -- * Stateful Type Primitives
types -- :: HOL cls thry [(String, TypeOp)]
, getTypeArityCtxt -- :: HOLContext thry -> String -> Maybe Int
, getTypeArity -- :: String -> HOL cls thry Int
, newType -- :: String -> Int -> HOL Theory thry ()
, mkType -- :: String -> [HOLType] -> HOL cls thry HOLType
, mkFunTy -- :: HOLType -> HOLType -> HOL cls thry HOLType
-- * Stateful Term Primitives
, constants -- :: HOL cls thry [(String, HOLTerm)]
, getConstType -- :: String -> HOL cls thry HOLType
, newConstant -- :: String -> HOLType -> HOL Theory thry ()
, mkConst -- :: TypeSubst l r =>
-- String -> [(l, r)] -> HOL cls thry HOLTerm
, mkConstFull -- :: String -> SubstTrip -> HOL cls thry HOLTerm
, mkEq -- :: HOLTerm -> HOLTerm -> HOL cls thry HOLTerm
-- * Stateful Theory Extension Primitives
, axioms -- :: HOL cls thry [(String, HOLThm)]
, getAxiom -- :: String -> HOL cls thry HOLThm
, newAxiom -- :: String -> HOLTerm -> HOL Theory thry HOLThm
, definitions -- :: HOL cls thry [HOLThm]
, newBasicDefinition -- :: HOLTerm -> HOL Theory thry HOLThm
, newBasicTypeDefinition -- :: String -> String -> String -> HOLThm ->
-- HOL Theory thry (HOLThm, HOLThm)
-- * Primitive Debugging System
, FlagDebug(..)
, warn -- :: Bool -> String -> HOL cls thry ()
, printDebugLn -- :: String -> HOL cls thry a -> HOL cls thry a
, printDebug -- :: String -> HOL cls thry a -> HOL cls thry a
-- * Monad Re-Export
, module HaskHOL.Core.State.Monad
) where
import HaskHOL.Core.Lib
import HaskHOL.Core.Kernel
import HaskHOL.Core.State.Monad
-- New flags and extensions
-- | Flag states whether or not to print debug statements.
newFlag "FlagDebug" True
newExtension "TypeConstants"
[| [("bool", tyOpBool), ("fun", tyOpFun)] :: [(String, TypeOp)] |]
newExtension "TermConstants" [| [("=", tmEq tyA)] :: [(String, HOLTerm)] |]
newExtension "TheAxioms" [| [] :: [(String, HOLThm)] |]
{-
Extensible state type for term definitions introduced via
newBasicDefinition.
-}
newExtension "TheCoreDefinitions" [| [] :: [HOLThm] |]
-- Stateful HOL Light Type Primitives
{-|
Retrieves the list of type constants from the current working theory. The
list contains pairs of strings recognized by the parser and the associated
type operator value, i.e.
> ("bool", tyOpBool)
-}
types :: HOL cls thry [(String, TypeOp)]
types =
do (TypeConstants tys) <- getExt
return tys
-- needed for parser
{-|
Retrieves the arity of a given type constant. Fails with 'Nothing' if the
provided type constant name is not defined in the provided context.
Note that this function takes a 'HOLContext' argument such that it can be
used outside of 'HOL' computations; for example, in the parser.
-}
getTypeArityCtxt :: HOLContext thry -> String -> Maybe Int
getTypeArityCtxt ctx name =
let (TypeConstants tys) = getExtCtxt ctx in
do tyOp <- lookup name tys
return . snd $ destTypeOp tyOp
{-|
A version of 'getTypeArityCtxt' that operates over the current working theory
of a 'HOL' computation. Throws a 'HOLException' if the provided type constant
name is not defined.
-}
getTypeArity :: String -> HOL cls thry Int
getTypeArity name =
do ctxt <- get
liftMaybe ("getTypeArity: type " ++ name ++ " has not been defined.") $
getTypeArityCtxt ctxt name
{-
Primitive type constant construction function. Used by newType and
newBasicTypeDefinition. Not exposed to the user.
-}
newType' :: String -> TypeOp -> HOL Theory thry ()
newType' name tyop =
do failWhen (can getTypeArity name) $
"newType: type " ++ name ++ " has already been declared."
modifyExt $ \ (TypeConstants consts) ->
TypeConstants $ (name, tyop) : consts
{-|
Constructs a new primitve type constant of a given name and arity. Also adds
this new type to the current working theory. Throws a 'HOLException' when a
type of the same name has already been declared.
-}
newType :: String -> Int -> HOL Theory thry ()
newType name arity =
newType' name $ newPrimTypeOp name arity
{-|
Constructs a type application given an operator name and a list of argument
types. If the provided name is not a currently defined type constant then
this function defaults it to a type operator variable. Throws a
'HOLException' in the following cases:
* A type operator's arity disagrees with the length of the argument list.
* A type operator is applied to zero arguments.
-}
mkType :: String -> [HOLType] -> HOL cls thry HOLType
mkType name args =
do (TypeConstants consts) <- getExt
case lookup name consts of
Just tyOp -> liftEither "mkType: type constructor application failed" $
tyApp tyOp args
Nothing ->
{- This seemed to be the easiest way to supress superfluous warnings
when parsing type operators. -}
do name' <- case name of
'_':x -> return x
_ -> printDebugLn
("warning - mkType: type " ++ name ++ " has " ++
"not been defined. Defaulting to type " ++
"operator variable.") $
return name
failWhen (return $ null args)
"mkType: type operator applied to zero args."
liftEither "mkType: type operator variable application failed" $
tyApp (mkTypeOpVar name') args
{-|
Constructs a function type safely using 'mkType'. Should never fail provided
that the initial value for type constants has not been modified.
-}
mkFunTy :: HOLType -> HOLType -> HOL cls thry HOLType
mkFunTy ty1 ty2 = mkType "fun" [ty1, ty2]
-- State for Constants
{-|
Retrieves the list of term constants from the current working theory. The
list contains pairs of strings recognized by the parser and the associated
term constant value, i.e.
> ("=", tmEq tyA)
-}
constants :: HOL cls thry [(String, HOLTerm)]
constants =
do (TermConstants consts) <- getExt
return consts
{-|
Retrieves the type of a given term constant. Throws a 'HOLException' if the
provided term constant name is not defined.
-}
getConstType :: String -> HOL cls thry HOLType
getConstType name =
do (TermConstants consts) <- getExt
tm <- liftMaybe "getConstType: not a constant name" $
lookup name consts
return $! typeOf tm
{-
Primitive term constant construction function. Used by newConstant,
newBasicDefinition, and newBasicTypeDefinition.
-}
newConstant' :: String -> HOLTerm -> HOL Theory thry ()
newConstant' name c =
do failWhen (can getConstType name) $
"newConstant: constant " ++ name ++ " has already been declared."
modifyExt $ \ (TermConstants consts) ->
TermConstants $ (name, c) : consts
{-|
Constructs a new primitive term constant of a given name and type. Also adds
this new term to the current working theory. Throws a 'HOLException' when a
term of the same name has already been declared.
-}
newConstant :: String -> HOLType -> HOL Theory thry ()
newConstant name ty =
newConstant' name $ newPrimConst name ty
{-|
Constructs a specific instance of a term constant when provided with its name
and a type substition environment. Throws a 'HOLException' in the
following cases:
* The instantiation as performed by 'instConst' fails.
* The provided name is not a currently defined constant.
-}
mkConst :: TypeSubst l r => String -> [(l, r)] -> HOL cls thry HOLTerm
mkConst name tyenv =
do (TermConstants consts) <- getExt
tm <- liftMaybe "mkConst: not a constant name" $
lookup name consts
liftMaybe "mkConst: instantiation failed" $
instConst tm tyenv
{-|
A version of 'mkConst' that accepts a triplet of type substitition
environments. Frequently used with the 'typeMatch' function.
-}
mkConstFull :: String -> SubstTrip -> HOL cls thry HOLTerm
mkConstFull name pat =
do (TermConstants consts) <- getExt
tm <- liftMaybe "mkConstFull: not a constant name" $
lookup name consts
liftMaybe "mkConstFull: instantiation failed" $
instConstFull tm pat
{-|
Safely creates an equality between two terms using 'mkConst' using the type of
the left hand side argument to perform the required instantiation. Throws a
'HOLException' in the case when the types of the two terms do not agree.
-}
mkEq :: HOLTerm -> HOLTerm -> HOL cls thry HOLTerm
mkEq l r =
let ty = typeOf l in
do eq <- mkConst "=" [(tyA, ty)]
liftEither "mkEq" $
liftM1 mkComb (mkComb eq l) r
-- State for Axioms
{-|
Retrieves the list of axioms from the current working theory. The list
contains pairs of string names and the axioms. This names exists such that
compile time operations have a tag with which they can use to extract axioms
from saved theories. See 'extractAxiom' for more details.
-}
axioms :: HOL cls thry [(String, HOLThm)]
axioms =
do (TheAxioms thms) <- getExt
return thms
{-|
Retrieves a specific axiom by name. Throws a 'HOLException' if there is no
axiom with the provided name in the current working theory.
-}
getAxiom :: String -> HOL cls thry HOLThm
getAxiom lbl =
do (TheAxioms thms) <- getExt
liftMaybe "getAxiom: axiom name not found" $
lookup lbl thms
{-|
Constructs a new axiom of a given name and conclusion term. Also adds this
new axiom to the current working theory. Throws a 'HOLException' in the
following cases:
* The provided term is not a proposition.
* An axiom with the provided name has already been declared.
-}
newAxiom :: String -> HOLTerm -> HOL Theory thry HOLThm
newAxiom name tm
| typeOf tm /= tyBool = fail "newAxiom: Not a proposition."
| otherwise =
do failWhen (can getAxiom name) $ "newAxiom: axiom with name " ++
name ++ " has already been declared."
let th = axiomThm tm
modifyExt $ \ (TheAxioms axs) -> TheAxioms $ (name, th) : axs
return th
-- State for Definitions
{-|
Retrieves the list of definitions from the current working theory. See
'newBasicDefinition' for more details.
-}
definitions :: HOL cls thry [HOLThm]
definitions =
do (TheCoreDefinitions defs) <- getExt
return defs
{-|
Introduces a definition of the form @c = t@ into the current working theory.
Throws a 'HOLException' when the definitional term is ill-formed. See
'newDefinedConst' for more details.
-}
newBasicDefinition :: HOLTerm -> HOL Theory thry HOLThm
newBasicDefinition tm =
do (c@(view -> Const name _ _), dth) <- liftEither "newBasicDefinition" $
newDefinedConst tm
newConstant' name c
modifyExt $ \ (TheCoreDefinitions defs) ->
TheCoreDefinitions $ dth : defs
return dth
{-|
Introduces a new type constant, and two associated term constants, into the
current working theory that is defined as an inhabited subset of an existing
type constant. Takes the following arguments:
* The name of the new type constant.
* The name of the new term constant that will be used to construct the type.
* The name of the new term constant that will be used to desctruct the type.
* A theorem that proves that the defining predicate has at least one
satisfying value.
Throws a 'HOLException' in the following cases:
* A term constant of either of the provided names has already been defined.
* A type constant of the provided name has already been defined.
See 'newDefinedTypeOp' for more details.
-}
newBasicTypeDefinition :: String -> String -> String -> HOLThm ->
HOL Theory thry (HOLThm, HOLThm)
newBasicTypeDefinition tyname absname repname dth =
do failWhen (return or <*> mapM (can getConstType) [absname, repname]) $
"newBasicTypeDefinition: Constant(s) " ++ absname ++ ", " ++ repname ++
" already in use."
(atyop, a, r, dth1, dth2) <- liftEither "newBasicTypeDefinition" $
newDefinedTypeOp tyname absname repname dth
failWhen (canNot (newType' tyname) atyop) $
"newBasicTypeDefinition: Type " ++ tyname ++ " already defined."
newConstant' absname a
newConstant' repname r
return (dth1, dth2)
-- Primitive Debugging Functions
{-|
Prints the provided string, with a new line, when the given boolean value is
true.
-}
warn :: Bool -> String -> HOL cls thry ()
warn flag str = when flag $ putStrLnHOL str
{-|
Prints the provided string, with a new line, when debugging is turned on, then
returns the given 'HOL' computation. A version of 'trace' for the 'HOL' monad
that is referentially transparent.
-}
printDebugLn :: String -> HOL cls thry a -> HOL cls thry a
printDebugLn = printDebugBase putStrLnHOL
-- | A version of printDebug that does not print a new line.
printDebug :: String -> HOL cls thry a -> HOL cls thry a
printDebug = printDebugBase putStrHOL
-- Abstracted out for future flexibility. Not exported.
printDebugBase :: (String -> HOL cls thry ()) -> String -> HOL cls thry a ->
HOL cls thry a
printDebugBase fn str x =
do debug <- getBenignFlag FlagDebug
if debug
then fn str >> x
else x
deriveLiftMany [ ''TypeConstants, ''TermConstants
, ''TheAxioms, ''TheCoreDefinitions ]