-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Instantiate structural induction schemas for algebraic data types -- @package structural-induction @version 0.2 -- | This package aims to perform the fiddly details of instantiating -- induction schemas for algebraic data types. The library is -- parameterised over the type of variables (v), constructors -- (c) and types (t). -- -- Let's see how it looks if you instantiate all these three with String -- and want to do induction over natural numbers. First, one needs to -- create a type environment, a TyEnv. For every type (we only -- have one), we need to list its constructors. For each constructor, we -- need to list its arguments and whether they are recursive or not. -- --
-- testEnv :: TyEnv String String
-- testEnv "Nat" = Just [ ("zero",[]) , ("succ",[Rec "Nat"]) ]
-- testEnv _ = Nothing
--
--
-- Now, we can use the subtermInduction to get induction
-- hypotheses which are just subterms of the conclusion. Normally, you
-- would translate the Terms from the proof Obligations to
-- some other representation, but there is also linearisation functions
-- included (linObligations, for instance.)
--
-- -- natInd :: [String] -> [Int] -> IO () -- natInd vars coords = putStrLn -- $ render -- $ linObligations strStyle -- $ unTag (\(x :~ i) -> x ++ show i) -- $ subtermInduction testEnv typed_vars coords -- where -- typed_vars = zip vars (repeat "Nat") ---- -- The library will create fresh variables for you (called Tagged -- variables), but you need to remove them, using for instance -- unTag. If you want to sync it with your own name supply, use -- unTagM or unTagMapM. -- -- An example invocation: -- --
-- *Mini> natInd ["X"] [0] -- P(zero). -- ! [X1 : Nat] : (P(X1) => P(succ(X1))). ---- -- This means to do induction on the zeroth coord (hence the 0), -- and the variable is called X. When using the library, it is up -- to you to translate the abstract P predicate to something -- meaningful. -- -- We can also do induction on several variables: -- --
-- *Mini> natInd ["X","Y"] [0,1] -- P(zero,zero). -- ! [Y3 : Nat] : (P(zero,Y3) => P(zero,succ(Y3))). -- ! [X1 : Nat] : (P(X1,zero) => P(succ(X1),zero)). -- ! [X1 : Nat,Y3 : Nat] : -- (P(X1,Y3) & -- P(X1,succ(Y3)) & -- P(succ(X1),Y3) -- => P(succ(X1),succ(Y3))). ---- -- In the last step case, all proper subterms of -- succ(X1),succ(Y3) are used as hypotheses. -- -- A bigger example is in example/Example.hs in the -- distribution. module Induction.Structural -- | Subterm induction: the induction hypotheses will contain the proper -- subterms of the conclusion. subtermInduction :: Ord c => TyEnv c t -> [(v, t)] -> [Int] -> [TaggedObligation c v t] -- | Does case analysis on a list of typed variables. This function is -- equal to removing all the hypotheses from subtermInduction. caseAnalysis :: TyEnv c t -> [(v, t)] -> [Int] -> [TaggedObligation c v t] -- | Quantifier lists are represented as tuples of variables and their -- type. -- -- Example: -- --
-- Obligation
-- { implicit = [(x,t1),(y,t2)]
-- , hypotheses = [([],[htm1,htm2])
-- ,([(z,t3)],[htm3,htm4])
-- ]
-- , conclusion = [tm1,tm2]
-- }
--
--
-- Corresponds to the formula:
--
-- forall (x : t1) (y : t2) . (P(htm1,htm2) & (forall (z : t3) .
-- P(htm3,htm4)) => P(tm1,tm2))
--
-- The implicit variables (x and y) can be viewed as
-- skolemised, and use these three formulae instead:
--
-- P(htm1,htm2).
--
-- forall (z : t3) . P(htm3,htm4).
--
-- ~ P(tm1,tm2).
data Obligation c v t
Obligation :: [(v, t)] -> [Hypothesis c v t] -> Predicate c v -> Obligation c v t
-- | Implicitly quantified variables (skolemised)
implicit :: Obligation c v t -> [(v, t)]
-- | Hypotheses, with explicitly quantified variables
hypotheses :: Obligation c v t -> [Hypothesis c v t]
-- | The induction conclusion
conclusion :: Obligation c v t -> Predicate c v
-- | Obligations with tagged variables (see Tagged and unTag)
type TaggedObligation c v t = Obligation c (Tagged v) t
-- | A list of terms.
--
-- Example: [tm1,tm2] corresponds to the formula
-- P(tm1,tm2)
type Predicate c v = [Term c v]
-- | Quantifier lists are represented as tuples of variables and their
-- type.
--
-- Example:
--
-- -- ([(x,t1),(y,t2)],[tm1,tm2]) ---- -- corresponds to the formula -- -- forall (x : t1) (y : t2) . P(tm1,tm2) type Hypothesis c v t = ([(v, t)], Predicate c v) -- | The simple term language only includes variables, constructors and -- functions. data Term c v Var :: v -> Term c v Con :: c -> [Term c v] -> Term c v -- | Induction on exponential data types yield assumptions with functions Fun :: v -> [Term c v] -> Term c v -- | Given a type, return either that you cannot do induction on is type -- (Nothing), or Just the constructors and a description of -- their arguments (see Arg). -- -- The function should instantiate type variables. For instance, -- if you look up the type [Nat], you should return the cons -- constructor with arguments Nat and [Nat] (see -- Arg). -- -- Examples of types not possible to do induction on are function spaces -- and type variables. For these, return Nothing. type TyEnv c t = t -> Maybe [(c, [Arg t])] -- | An argument to a constructor can be recursive (Rec) or -- non-recursive (NonRec). Induction hypotheses will be asserted -- for Rec arguments. -- -- For instance, when doing induction on [a], then (:) -- has two arguments, NonRec a and Rec [a]. On the -- other hand, if doing induction on [Nat], then (:) -- has NonRec Nat and Rec [Nat]. -- -- Data types can also be exponential. Consider -- --
-- data Ord = Zero | Succ Ord | Lim (Nat -> Ord) ---- -- Here, the Lim constructor is exponential. If we describe -- types and constructors with strings, the constructors for this data -- type is: -- --
-- [ ("Zero",[])
-- , ("Succ",[Rec "Ord"])
-- , ("Lim",[Exp ("Nat -> Ord") ["Nat"])
-- ]
--
--
-- The first argument to Exp is the type of the function, and the
-- second argument are the arguments to the function.
data Arg t
Rec :: t -> Arg t
NonRec :: t -> Arg t
Exp :: t -> [t] -> Arg t
-- | Cheap way of introducing fresh variables. The Eq and Ord
-- instances only uses the Integer tag.
data Tagged v
(:~) :: v -> Integer -> Tagged v
-- | The Integer tag
tag :: Tagged v -> Integer
-- | Removing tagged (fresh) variables
unTag :: (Tagged v -> v') -> [TaggedObligation c v t] -> [Obligation c v' t]
-- | Removing tagged (fresh) variables in a monad. The remove function is
-- exectued at every occurence of a tagged variable. This is
-- useful if you want to sync it with your own name supply monad.
unTagM :: Applicative m => (Tagged v -> m v') -> [TaggedObligation c v t] -> m [Obligation c v' t]
-- | Remove tagged (fresh) variables in a monad. The remove function is
-- exectued only once for each tagged variable, and a Map
-- of renamings is returned. This is useful if you want to sync it with
-- your own name supply monad.
unTagMapM :: (Functor m, Monad m) => (Tagged v -> m v') -> [TaggedObligation c v t] -> m ([Obligation c v' t], Map (Tagged v) v')
-- | Linearises a list of Obligation, using a given Style.
linObligations :: Style c v t -> [Obligation c v t] -> Doc
-- | Linearises an Obligation using a given Style. The output
-- format is inspired by TPTP, but with typed quantifiers.
linObligation :: Style c v t -> Obligation c v t -> Doc
-- | Linearises a Term using a given Style.
linTerm :: Style c v t -> Term c v -> Doc
-- | Functions for linearising constructors (linc), variables
-- (linv) and types (lint).
data Style c v t
Style :: (c -> Doc) -> (v -> Doc) -> (t -> Doc) -> Style c v t
linc :: Style c v t -> c -> Doc
linv :: Style c v t -> v -> Doc
lint :: Style c v t -> t -> Doc
-- | An example style where constructors, variables and types are
-- represented as String.
strStyle :: Style String String String
-- | Render the Doc to a String using the default Style.
render :: Doc -> String
-- | A document of height 1 containing a literal string. text
-- satisfies the following laws:
--
--
--
-- The side condition on the last law is necessary because
-- text "" has height 1, while empty has no
-- height.
text :: String -> Doc