File: Mathlib/Tactic/Lift.lean

full_name: CanLift
code: /-- A class specifying that you can lift elements from `α` to `β` assuming `cond` is true.
  Used by the tactic `lift`. -/
class CanLift (α β : Sort*) (coe : outParam <| β → α) (cond : outParam <| α → Prop) : Prop where
  /-- An element of `α` that satisfies `cond` belongs to the range of `coe`. -/
  prf : ∀ x : α, cond x → ∃ y : β, coe y = x
goal: Prop

full_name: CanLift.prf
code: /-- A class specifying that you can lift elements from `α` to `β` assuming `cond` is true.
  Used by the tactic `lift`. -/
class CanLift (α β : Sort*) (coe : outParam <| β → α) (cond : outParam <| α → Prop) : Prop where
  /-- An element of `α` that satisfies `cond` belongs to the range of `coe`. -/
  prf : ∀ x : α, cond x → ∃ y : β, coe y = x
goal: cond x → ∃ y, coe y = x

full_name: instCanLiftIntNatCastLeOfNat
code: instance : CanLift Int Nat (fun n : Nat ↦ n) (0 ≤ ·) 
goal: CanLift Int Nat (fun n => ↑n) fun x => 0 ≤ x

full_name: Pi.canLift
code: /-- Enable automatic handling of pi types in `CanLift`. -/
instance Pi.canLift (ι : Sort*) (α β : ι → Sort*) (coe : ∀ i, β i → α i) (P : ∀ i, α i → Prop)
    [∀ i, CanLift (α i) (β i) (coe i) (P i)] :
    CanLift (∀ i, α i) (∀ i, β i) (fun f i ↦ coe i (f i)) fun f ↦ ∀ i, P i (f i) 
goal: CanLift ((i : ι) → α i) ((i : ι) → β i) (fun f i => coe i (f i)) fun f => ∀ (i : ι), P i (f i)

full_name: Subtype.exists_pi_extension
code: theorem Subtype.exists_pi_extension {ι : Sort*} {α : ι → Sort*} [ne : ∀ i, Nonempty (α i)]
    {p : ι → Prop} (f : ∀ i : Subtype p, α i) :
    ∃ g : ∀ i : ι, α i, (fun i : Subtype p => g i) = f 
goal: ∃ g, (fun i => g i.val) = f

full_name: PiSubtype.canLift
code: instance PiSubtype.canLift (ι : Sort*) (α : ι → Sort*) [∀ i, Nonempty (α i)] (p : ι → Prop) :
    CanLift (∀ i : Subtype p, α i) (∀ i, α i) (fun f i => f i) fun _ => True 
goal: CanLift ((i : Subtype p) → α i.val) ((i : ι) → α i) (fun f i => f i.val) fun x => True

full_name: PiSubtype.canLift'
code: instance PiSubtype.canLift' (ι : Sort*) (α : Sort*) [Nonempty α] (p : ι → Prop) :
    CanLift (Subtype p → α) (ι → α) (fun f i => f i) fun _ => True 
goal: CanLift (Subtype p → α) (ι → α) (fun f i => f i.val) fun x => True

full_name: Subtype.canLift
code: instance Subtype.canLift {α : Sort*} (p : α → Prop) :
    CanLift α { x // p x } Subtype.val p 
goal: CanLift α { x // p x } Subtype.val p

full_name: Mathlib.Tactic.lift
code: /-- Lift an expression to another type.
* Usage: `'lift' expr 'to' expr ('using' expr)? ('with' id (id id?)?)?`.
* If `n : ℤ` and `hn : n ≥ 0` then the tactic `lift n to ℕ using hn` creates a new
  constant of type `ℕ`, also named `n` and replaces all occurrences of the old variable `(n : ℤ)`
  with `↑n` (where `n` in the new variable). It will remove `n` and `hn` from the context.
  + So for example the tactic `lift n to ℕ using hn` transforms the goal
    `n : ℤ, hn : n ≥ 0, h : P n ⊢ n = 3` to `n : ℕ, h : P ↑n ⊢ ↑n = 3`
    (here `P` is some term of type `ℤ → Prop`).
* The argument `using hn` is optional, the tactic `lift n to ℕ` does the same, but also creates a
  new subgoal that `n ≥ 0` (where `n` is the old variable).
  This subgoal will be placed at the top of the goal list.
  + So for example the tactic `lift n to ℕ` transforms the goal
    `n : ℤ, h : P n ⊢ n = 3` to two goals
    `n : ℤ, h : P n ⊢ n ≥ 0` and `n : ℕ, h : P ↑n ⊢ ↑n = 3`.
* You can also use `lift n to ℕ using e` where `e` is any expression of type `n ≥ 0`.
* Use `lift n to ℕ with k` to specify the name of the new variable.
* Use `lift n to ℕ with k hk` to also specify the name of the equality `↑k = n`. In this case, `n`
  will remain in the context. You can use `rfl` for the name of `hk` to substitute `n` away
  (i.e. the default behavior).
* You can also use `lift e to ℕ with k hk` where `e` is any expression of type `ℤ`.
  In this case, the `hk` will always stay in the context, but it will be used to rewrite `e` in
  all hypotheses and the target.
  + So for example the tactic `lift n + 3 to ℕ using hn with k hk` transforms the goal
    `n : ℤ, hn : n + 3 ≥ 0, h : P (n + 3) ⊢ n + 3 = 2 * n` to the goal
    `n : ℤ, k : ℕ, hk : ↑k = n + 3, h : P ↑k ⊢ ↑k = 2 * n`.
* The tactic `lift n to ℕ using h` will remove `h` from the context. If you want to keep it,
  specify it again as the third argument to `with`, like this: `lift n to ℕ using h with n rfl h`.
* More generally, this can lift an expression from `α` to `β` assuming that there is an instance
  of `CanLift α β`. In this case the proof obligation is specified by `CanLift.prf`.
* Given an instance `CanLift β γ`, it can also lift `α → β` to `α → γ`; more generally, given
  `β : Π a : α, Type*`, `γ : Π a : α, Type*`, and `[Π a : α, CanLift (β a) (γ a)]`, it
  automatically generates an instance `CanLift (Π a, β a) (Π a, γ a)`.

`lift` is in some sense dual to the `zify` tactic. `lift (z : ℤ) to ℕ` will change the type of an
integer `z` (in the supertype) to `ℕ` (the subtype), given a proof that `z ≥ 0`;
propositions concerning `z` will still be over `ℤ`. `zify` changes propositions about `ℕ` (the
subtype) to propositions about `ℤ` (the supertype), without changing the type of any variable.
-/
syntax (name := lift) "lift " term " to " term (" using " term)?
  (" with " ident (ppSpace colGt ident)? (ppSpace colGt ident)?)? : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Lift.getInst
code: /-- Generate instance for the `lift` tactic. -/
def Lift.getInst (old_tp new_tp : Expr) : MetaM (Expr × Expr × Expr) 
goal: Lean.MetaM (Lean.Expr × Lean.Expr × Lean.Expr)

full_name: Mathlib.Tactic.Lift.main
code: /-- Main function for the `lift` tactic. -/
def Lift.main (e t : TSyntax `term) (hUsing : Option (TSyntax `term))
    (newVarName newEqName : Option (TSyntax `ident)) (keepUsing : Bool) : TacticM Unit 
goal: Lean.Elab.Tactic.TacticM Unit

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_Lift___elabRules_Mathlib_Tactic_lift_1
code: elab_rules : tactic
  | `(tactic| lift $e to $t $[using $h]?) => withMainContext <| Lift.main e t h none none False
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_Lift___elabRules_Mathlib_Tactic_lift_2
code: elab_rules : tactic | `(tactic| lift $e to $t $[using $h]?
    with $newVarName) => withMainContext <| Lift.main e t h newVarName none False
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_Lift___elabRules_Mathlib_Tactic_lift_3
code: elab_rules : tactic | `(tactic| lift $e to $t $[using $h]?
    with $newVarName $newEqName) => withMainContext <| Lift.main e t h newVarName newEqName False
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_Lift___elabRules_Mathlib_Tactic_lift_4
code: elab_rules : tactic | `(tactic| lift $e to $t $[using $h]?
    with $newVarName $newEqName $newPrfName) => withMainContext do
  if h.isNone then Lift.main e t h newVarName newEqName False
  else
    let some h := h | unreachable!
    if h.raw == newPrfName then Lift.main e t h newVarName newEqName True
    else Lift.main e t h newVarName newEqName False
goal: Lean.Elab.Tactic.Tactic