hermit-0.4.0.0: src/HERMIT/Dictionary/Induction.hs
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables, MultiWayIf #-}
module HERMIT.Dictionary.Induction
( -- * Induction
inductionCaseSplit
-- , inductionOnT
-- , listInductionOnT
)
where
import Control.Arrow
-- import Data.List (delete)
import HERMIT.Context
import HERMIT.Core
import HERMIT.GHC
import HERMIT.Kure
import HERMIT.Monad
-- import HERMIT.Utilities (soleElement)
import HERMIT.Dictionary.Common
import HERMIT.Dictionary.Local.Case (caseSplitInlineR)
-- import HERMIT.Dictionary.Reasoning
import HERMIT.Dictionary.Undefined
------------------------------------------------------------------------------
-- TODO: Warning, this is very experimental
------------------------------------------------------------------------------
inductionCaseSplit :: (ExtendPath c Crumb, ReadPath c Crumb, AddBindings c, ReadBindings c, HasGlobalRdrEnv c) => [Var] -> Id -> CoreExpr -> CoreExpr -> Translate c HermitM x [(Maybe DataCon,[Var],CoreExpr,CoreExpr)]
inductionCaseSplit vs i lhsE rhsE =
do -- first construct an expression containing both the LHS and the RHS
il <- constT $ newIdH "dummyL" (exprKindOrType lhsE)
ir <- constT $ newIdH "dummyR" (exprKindOrType rhsE)
let contrivedExpr = Let (NonRec il lhsE)
(Let (NonRec ir rhsE)
(Var i)
)
-- then case split on the identifier, inlining the pattern
-- we consider the other universally quantified variables to be in scope while doing so
Case _ _ _ alts <- withVarsInScope vs (caseSplitInlineR (==i)) <<< return contrivedExpr
let dataConCases = map compressAlts alts
lhsUndefined <- extractR (replaceIdWithUndefinedR i) <<< return lhsE
rhsUndefined <- extractR (replaceIdWithUndefinedR i) <<< return rhsE
let undefinedCase = (Nothing,[],lhsUndefined,rhsUndefined)
return (undefinedCase : dataConCases)
where
compressAlts :: CoreAlt -> (Maybe DataCon,[Var],CoreExpr,CoreExpr)
compressAlts (DataAlt con,bs,Let (NonRec _ lhsE') (Let (NonRec _ rhsE') _)) = (Just con,bs,lhsE',rhsE')
compressAlts _ = error "Bug in inductionCaseSplit"
-- NOTE: Most of the Induction infrastructure has moved to HERMIT/Shell/Proof.hs
-- -- | A general induction principle. TODO: Is this valid for infinite data types? Probably not.
-- inductionOnT :: forall c. (AddBindings c, ReadBindings c, ReadPath c Crumb, ExtendPath c Crumb, Walker c Core)
-- => (Id -> Bool) -> (DataCon -> [BiRewrite c HermitM CoreExpr] -> CoreExprEqualityProof c HermitM) -> Translate c HermitM CoreExprEquality ()
-- inductionOnT idPred genCaseAltProofs = prefixFailMsg "Induction failed: " $
-- do eq@(CoreExprEquality bs lhs rhs) <- idR
-- i <- setFailMsg "specified identifier is not universally quantified in this equality lemma." $ soleElement (filter idPred bs)
-- cases <- inductionCaseSplit bs i lhs rhs
-- -- TODO: will this work if vs contains TyVars or CoVars? Maybe we need to sort the Vars in order: TyVars; CoVars; Ids.
-- let verifyInductiveCaseT :: (DataCon,[Var],CoreExpr,CoreExpr) -> Translate c HermitM x ()
-- verifyInductiveCaseT (con,vs,lhsE,rhsE) =
-- let vs_matching_i_type = filter (typeAlphaEq (varType i) . varType) vs
-- eqs = [ discardUniVars (instantiateCoreExprEq [(i,Var i')] eq) | i' <- vs_matching_i_type ]
-- brs = map birewrite eqs -- These eqs now have no universally quantified variables.
-- -- Thus they can only be used on variables in the induction hypothesis.
-- -- TODO: consider whether this is unneccassarily restrictive
-- caseEq = CoreExprEquality (delete i bs ++ vs) lhsE rhsE
-- in return caseEq >>> verifyCoreExprEqualityT (genCaseAltProofs con brs)
-- mapM_ verifyInductiveCaseT cases
-- -- | An induction principle for lists.
-- listInductionOnT :: (AddBindings c, ReadBindings c, ReadPath c Crumb, ExtendPath c Crumb, Walker c Core)
-- => (Id -> Bool) -- Id to case split on
-- -> CoreExprEqualityProof c HermitM -- proof for [] case
-- -> (BiRewrite c HermitM CoreExpr -> CoreExprEqualityProof c HermitM) -- proof for (:) case, given smaller proof
-- -> Translate c HermitM CoreExprEquality ()
-- listInductionOnT idPred nilCaseProof consCaseProof = inductionOnT idPred $ \ con brs ->
-- if | con == nilDataCon -> case brs of
-- [] -> nilCaseProof
-- _ -> error "Bug!"
-- | con == consDataCon -> case brs of
-- [br] -> consCaseProof br
-- _ -> error "Bug!"
-- | otherwise -> let msg = "Mystery constructor, this is a bug."
-- in (fail msg, fail msg)
------------------------------------------------------------------------------