File: .lake/packages/lean4/src/lean/Lean/Meta/Tactic/FunInd.lean

full_name: Lean.Tactic.FunInd.removeLamda
code: /-- Opens the body of a lambda, _without_ putting the free variable into the local context.
This is used when replacing parameters with different expressions.
This way it will not be picked up by metavariables.
-/
def removeLamda {n} [MonadLiftT MetaM n] [MonadError n] [MonadNameGenerator n] [Monad n] {α} (e : Expr) (k : FVarId → Expr → n α) : n α 
goal: n α

full_name: Lean.Tactic.FunInd.mkFst
code: /-- `PProd.fst` or `And.left` -/
def mkFst (e : Expr) : MetaM Expr 
goal: Lean.MetaM Lean.Expr

full_name: Lean.Tactic.FunInd.mkSnd
code: /-- `PProd.snd` or `And.right` -/
def mkSnd (e : Expr) : MetaM Expr 
goal: Lean.MetaM Lean.Expr

full_name: Lean.Tactic.FunInd.isPProdProj
code: /--
Structural recursion only:
Recognizes `oldIH.fst.snd a₁ a₂` and returns `newIH.fst.snd`.
Possibly switching from `PProd.fst` to `And.left` if needed
 -/
partial def isPProdProj (oldIH newIH : FVarId) (e : Expr) : MetaM (Option Expr) 
goal: Lean.MetaM (Option Lean.Expr)

full_name: Lean.Tactic.FunInd.isPProdProjWithArgs
code: /--
Structural recursion only:
Recognizes `oldIH.fst.snd a₁ a₂` and returns `newIH.fst.snd` and `#[a₁, a₂]`.
-/
def isPProdProjWithArgs (oldIH newIH : FVarId) (e : Expr) : MetaM (Option (Expr × Array Expr)) 
goal: Lean.MetaM (Option (Lean.Expr × Array Lean.Expr))

full_name: Lean.Tactic.FunInd.foldCalls
code: /--
Replace calls to oldIH back to calls to the original function. At the end, if `oldIH` occurs, an
error is thrown.

The `newIH` will not show up in the output of `foldCalls`, we use it as a helper to infer the
argument of nested recursive calls when we have structural recursion.
-/
partial def foldCalls (is_wf : Bool) (fn : Expr) (oldIH newIH : FVarId) (e : Expr) : MetaM Expr 
goal: Lean.MetaM Lean.Expr

full_name: Lean.Tactic.FunInd.collectIHs
code: partial def collectIHs (is_wf : Bool) (fn : Expr) (oldIH newIH : FVarId) (e : Expr) : MetaM (Array Expr) 
goal: Lean.MetaM (Array Lean.Expr)

full_name: Lean.Tactic.FunInd.deduplicateIHs
code: def deduplicateIHs (vals : Array Expr) : MetaM (Array Expr) 
goal: Lean.MetaM (Array Lean.Expr)

full_name: Lean.Tactic.FunInd.assertIHs
code: def assertIHs (vals : Array Expr) (mvarid : MVarId) : MetaM MVarId 
goal: Lean.MetaM Lean.MVarId

full_name: Lean.Tactic.FunInd.substVarAfter
code: /--
Substitutes equations, but makes sure to only substitute variables introduced after the motive
as the motive could depend on anything before, and `substVar` would happily drop equations
about these fixed parameters.
-/
def substVarAfter (mvarId : MVarId) (x : FVarId) : MetaM MVarId 
goal: Lean.MetaM Lean.MVarId

full_name: Lean.Tactic.FunInd.M
code: /--
Helper monad to traverse the function body, collecting the cases as mvars
-/
abbrev M α 
goal: Type

full_name: Lean.Tactic.FunInd.buildInductionCase
code: /-- Base case of `buildInductionBody`: Construct a case for the final induction hypthesis.  -/
def buildInductionCase (is_wf : Bool) (fn : Expr) (oldIH newIH : FVarId) (toClear toPreserve : Array FVarId)
    (goal : Expr) (IHs : Array Expr) (e : Expr) : M Expr 
goal: Lean.Tactic.FunInd.M Lean.Expr

full_name: Lean.Tactic.FunInd.mkLambdaFVarsMasked
code: /--
Like `mkLambdaFVars (usedOnly := true)`, but

 * silently skips expression in `xs` that are not `.isFVar`
 * returns a mask (same size as `xs`) indicating which variables have been abstracted
   (`true` means was abstracted).

The result `r` can be applied with `r.beta (maskArray mask args)`.

We use this when generating the functional induction principle to refine the goal through a `match`,
here `xs` are the discriminans of the `match`.
We do not expect non-trivial discriminants to appear in the goal (and if they do, the user will
get a helpful equality into the context).
-/
def mkLambdaFVarsMasked (xs : Array Expr) (e : Expr) : MetaM (Array Bool × Expr) 
goal: Lean.MetaM (Array Bool × Lean.Expr)

full_name: Lean.Tactic.FunInd.maskArray
code: /-- `maskArray mask xs` keeps those `x` where the corresponding entry in `mask` is `true` -/
def maskArray {α} (mask : Array Bool) (xs : Array α) : Array α 
goal: Array α

full_name: Lean.Tactic.FunInd.buildInductionBody
code: /--
Builds an expression of type `goal` by replicating the expression `e` into its tail-call-positions,
where it calls `buildInductionCase`. Collects the cases of the final induction hypothesis
as `MVars` as it goes.
-/
partial def buildInductionBody (is_wf : Bool) (fn : Expr) (toClear toPreserve : Array FVarId)
    (goal : Expr) (oldIH newIH : FVarId) (IHs : Array Expr) (e : Expr) : M Expr 
goal: Lean.Tactic.FunInd.M Lean.Expr

full_name: Lean.Tactic.FunInd.abstractIndependentMVars
code: /--
Given an expression `e` with metavariables
* collects all these meta-variables,
* lifts them to the current context by reverting all local declarations up to `x`
* introducing a local variable for each of the meta variable
* assigning that local variable to the mvar
* and finally lambda-abstracting over these new local variables.

This operation only works if the metavariables are independent from each other.

The resulting meta variable assignment is no longer valid (mentions out-of-scope
variables), so after this operations, terms that still mention these meta variables must not
be used anymore.

We are not using `mkLambdaFVars` on mvars directly, nor `abstractMVars`, as these at the moment
do not handle delayed assignemnts correctly.
-/
def abstractIndependentMVars (mvars : Array MVarId) (x : FVarId) (e : Expr) : MetaM Expr 
goal: Lean.MetaM Lean.Expr

full_name: Lean.Tactic.FunInd.motiveUniverseParamPos
code: def motiveUniverseParamPos (declName : Name) : MetaM (Option Nat) 
goal: Lean.MetaM (Option Nat)

full_name: Lean.Tactic.FunInd.findRecursor.err
code: /--
This function looks that the body of a recursive function and looks for either users of
`fix`, `fixF` or a `.brecOn`, and abstracts over the differences between them. It passes
to the continuation

* whether we are using well-founded recursion
* the fixed parameters of the function body
* the varying parameters of the function body (this includes both the targets of the
  recursion and extra parameters passed to the recursor)
* the position of the motive/induction hypothesis in the body's arguments
* the body, as passed to the recursor. Expected to be a lambda that takes the
  varying paramters and the motive
* a function to re-assemble the call with a new Motive. The resulting expression expects
  the new body next, so that the expected type of the body can be inferred
* a function to finish assembling the call with the new body.
-/
def findRecursor {α} (name : Name) (varNames : Array Name) (e : Expr)
    (k :(is_wf : Bool) →
        (fixedParams : Array Expr) →
        (varyingParams : Array Expr) →
        (motivePosInBody : Nat) →
        (body : Expr) →
        (mkAppMotive : Expr → MetaM Expr) →
        (mkAppBody : Expr → Expr → Expr) →
        MetaM α) :
    MetaM α 
goal: Lean.MetaM α

full_name: Lean.Tactic.FunInd.findRecursor
code: /--
This function looks that the body of a recursive function and looks for either users of
`fix`, `fixF` or a `.brecOn`, and abstracts over the differences between them. It passes
to the continuation

* whether we are using well-founded recursion
* the fixed parameters of the function body
* the varying parameters of the function body (this includes both the targets of the
  recursion and extra parameters passed to the recursor)
* the position of the motive/induction hypothesis in the body's arguments
* the body, as passed to the recursor. Expected to be a lambda that takes the
  varying paramters and the motive
* a function to re-assemble the call with a new Motive. The resulting expression expects
  the new body next, so that the expected type of the body can be inferred
* a function to finish assembling the call with the new body.
-/
def findRecursor {α} (name : Name) (varNames : Array Name) (e : Expr)
    (k :(is_wf : Bool) →
        (fixedParams : Array Expr) →
        (varyingParams : Array Expr) →
        (motivePosInBody : Nat) →
        (body : Expr) →
        (mkAppMotive : Expr → MetaM Expr) →
        (mkAppBody : Expr → Expr → Expr) →
        MetaM α) :
    MetaM α 
goal: Lean.MetaM α

full_name: Lean.Tactic.FunInd.deriveUnaryInduction
code: /--
Given a definition `foo` defined via `WellFounded.fixF`, derive a suitable induction principle
`foo.induct` for it. See module doc for details.
 -/
def deriveUnaryInduction (name : Name) : MetaM Name 
goal: Lean.MetaM Lean.Name

full_name: Lean.Tactic.FunInd.cleanPackedArgs
code: /--
In the type of `value`, reduces
* Beta-redexes
* `PSigma.casesOn (PSigma.mk a b) (fun x y => k x y)  -->  k a b`
* `PSum.casesOn (PSum.inl x) k₁ k₂                    -->  k₁ x`
* `foo._unary (PSum.inl (PSigma.mk a b))              -->  foo a b`
and then wraps `value` in an appropriate type hint.
-/
def cleanPackedArgs (eqnInfo : WF.EqnInfo) (value : Expr) : MetaM Expr 
goal: Lean.MetaM Lean.Expr

full_name: Lean.Tactic.FunInd.unpackMutualInduction
code: /--
Takes an induction principle where the motive is a `PSigma`/`PSum` type and
unpacks it into a n-ary and (possibly) joint induction principle.
-/
def unpackMutualInduction (eqnInfo : WF.EqnInfo) (unaryInductName : Name) : MetaM Name 
goal: Lean.MetaM Lean.Name

full_name: Lean.Tactic.FunInd.deriveUnpackedInduction
code: /-- Given `foo._unary.induct`, define `foo.mutual_induct` and then `foo.induct`, `bar.induct`, … -/
def deriveUnpackedInduction (eqnInfo : WF.EqnInfo) (unaryInductName : Name): MetaM Unit 
goal: Lean.MetaM Unit

full_name: Lean.Tactic.FunInd.deriveInduction
code: /--
Given a recursively defined function `foo`, derives `foo.induct`. See the module doc for details.
-/
def deriveInduction (name : Name) : MetaM Unit 
goal: Lean.MetaM Unit

full_name: Lean.Tactic.FunInd.isFunInductName
code: def isFunInductName (env : Environment) (name : Name) : Bool 
goal: Bool

full_name: Lean.Tactic.FunInd.initFn._@..lake.packages.lean4.src.lean.Lean.Meta.Tactic.FunInd._hyg.12802
code: builtin_initialize
  registerReservedNamePredicate isFunInductName

  registerReservedNameAction fun name => do
    if isFunInductName (← getEnv) name then
      let .str p _ := name | return false
      MetaM.run' <| deriveInduction p
      return true
    return false
goal: IO Unit