File: .lake/packages/lean4/src/lean/Init/GetElem.lean

full_name: outOfBounds
code: @[never_extract]
def outOfBounds [Inhabited α] : α 
goal: α

full_name: outOfBounds_eq_default
code: theorem outOfBounds_eq_default [Inhabited α] : (outOfBounds : α) = default 
goal: outOfBounds = default

full_name: GetElem
code: /--
The classes `GetElem` and `GetElem?` implement lookup notation,
specifically `xs[i]`, `xs[i]?`, `xs[i]!`, and `xs[i]'p`.

Both classes are indexed by types `coll`, `idx`, and `elem` which are
the collection, the index, and the element types.
A single collection may support lookups with multiple index
types. The relation `valid` determines when the index is guaranteed to be
valid; lookups of valid indices are guaranteed not to fail.

For example, an instance for arrays looks like
`GetElem (Array α) Nat α (fun xs i => i < xs.size)`. In other words, given an
array `xs` and a natural number `i`, `xs[i]` will return an `α` when `valid xs i`
holds, which is true when `i` is less than the size of the array. `Array`
additionally supports indexing with `USize` instead of `Nat`.
In either case, because the bounds are checked at compile time,
no runtime check is required.

Given `xs[i]` with `xs : coll` and `i : idx`, Lean looks for an instance of
`GetElem coll idx elem valid` and uses this to infer the type of the return
value `elem` and side condition `valid` required to ensure `xs[i]` yields
a valid value of type `elem`. The tactic `get_elem_tactic` is
invoked to prove validity automatically. The `xs[i]'p` notation uses the
proof `p` to satisfy the validity condition.
If the proof `p` is long, it is often easier to place the
proof in the context using `have`, because `get_elem_tactic` tries
`assumption`.


The proof side-condition `valid xs i` is automatically dispatched by the
`get_elem_tactic` tactic; this tactic can be extended by adding more clauses to
`get_elem_tactic_trivial` using `macro_rules`.

`xs[i]?` and `xs[i]!` do not impose a proof obligation; the former returns
an `Option elem`, with `none` signalling that the value isn't present, and
the latter returns `elem` but panics if the value isn't there, returning
`default : elem` based on the `Inhabited elem` instance.
These are provided by the `GetElem?` class, for which there is a default instance
generated from a `GetElem` class as long as `valid xs i` is always decidable.

Important instances include:
  * `arr[i] : α` where `arr : Array α` and `i : Nat` or `i : USize`: does array
    indexing with no runtime bounds check and a proof side goal `i < arr.size`.
  * `l[i] : α` where `l : List α` and `i : Nat`: index into a list, with proof
    side goal `i < l.length`.

-/
class GetElem (coll : Type u) (idx : Type v) (elem : outParam (Type w))
              (valid : outParam (coll → idx → Prop)) where
  /--
  The syntax `arr[i]` gets the `i`'th element of the collection `arr`. If there
  are proof side conditions to the application, they will be automatically
  inferred by the `get_elem_tactic` tactic.
  -/
  getElem (xs : coll) (i : idx) (h : valid xs i) : elem
goal: Type (max (max u v) w)

full_name: GetElem.getElem
code: /--
The classes `GetElem` and `GetElem?` implement lookup notation,
specifically `xs[i]`, `xs[i]?`, `xs[i]!`, and `xs[i]'p`.

Both classes are indexed by types `coll`, `idx`, and `elem` which are
the collection, the index, and the element types.
A single collection may support lookups with multiple index
types. The relation `valid` determines when the index is guaranteed to be
valid; lookups of valid indices are guaranteed not to fail.

For example, an instance for arrays looks like
`GetElem (Array α) Nat α (fun xs i => i < xs.size)`. In other words, given an
array `xs` and a natural number `i`, `xs[i]` will return an `α` when `valid xs i`
holds, which is true when `i` is less than the size of the array. `Array`
additionally supports indexing with `USize` instead of `Nat`.
In either case, because the bounds are checked at compile time,
no runtime check is required.

Given `xs[i]` with `xs : coll` and `i : idx`, Lean looks for an instance of
`GetElem coll idx elem valid` and uses this to infer the type of the return
value `elem` and side condition `valid` required to ensure `xs[i]` yields
a valid value of type `elem`. The tactic `get_elem_tactic` is
invoked to prove validity automatically. The `xs[i]'p` notation uses the
proof `p` to satisfy the validity condition.
If the proof `p` is long, it is often easier to place the
proof in the context using `have`, because `get_elem_tactic` tries
`assumption`.


The proof side-condition `valid xs i` is automatically dispatched by the
`get_elem_tactic` tactic; this tactic can be extended by adding more clauses to
`get_elem_tactic_trivial` using `macro_rules`.

`xs[i]?` and `xs[i]!` do not impose a proof obligation; the former returns
an `Option elem`, with `none` signalling that the value isn't present, and
the latter returns `elem` but panics if the value isn't there, returning
`default : elem` based on the `Inhabited elem` instance.
These are provided by the `GetElem?` class, for which there is a default instance
generated from a `GetElem` class as long as `valid xs i` is always decidable.

Important instances include:
  * `arr[i] : α` where `arr : Array α` and `i : Nat` or `i : USize`: does array
    indexing with no runtime bounds check and a proof side goal `i < arr.size`.
  * `l[i] : α` where `l : List α` and `i : Nat`: index into a list, with proof
    side goal `i < l.length`.

-/
class GetElem (coll : Type u) (idx : Type v) (elem : outParam (Type w))
              (valid : outParam (coll → idx → Prop)) where
  /--
  The syntax `arr[i]` gets the `i`'th element of the collection `arr`. If there
  are proof side conditions to the application, they will be automatically
  inferred by the `get_elem_tactic` tactic.
  -/
  getElem (xs : coll) (i : idx) (h : valid xs i) : elem
goal: elem

full_name: «term__[_]»
code: @[inherit_doc getElem]
syntax:max term noWs "[" withoutPosition(term) "]" : term
goal: Lean.TrailingParserDescr

full_name: «_aux_.lake_packages_lean4_src_lean_Init_GetElem___macroRules_term__[_]_1»
code: macro_rules | `($x[$i]) => `(getElem $x $i (by get_elem_tactic))
goal: Lean.Macro

full_name: «term__[_]'_»
code: @[inherit_doc getElem]
syntax term noWs "[" withoutPosition(term) "]'" term:max : term
goal: Lean.TrailingParserDescr

full_name: «_aux_.lake_packages_lean4_src_lean_Init_GetElem___macroRules_term__[_]'__1»
code: macro_rules | `($x[$i]'$h) => `(getElem $x $i $h)
goal: Lean.Macro

full_name: decidableGetElem?
code: /-- Helper function for implementation of `GetElem?.getElem?`. -/
abbrev decidableGetElem? [GetElem coll idx elem valid] (xs : coll) (i : idx) [Decidable (valid xs i)] :
    Option elem 
goal: Option elem

full_name: GetElem?.getElem?
code: @[inherit_doc GetElem]
class GetElem? (coll : Type u) (idx : Type v) (elem : outParam (Type w))
    (valid : outParam (coll → idx → Prop)) extends GetElem coll idx elem valid where
  /--
  The syntax `arr[i]?` gets the `i`'th element of the collection `arr`,
  if it is present (and wraps it in `some`), and otherwise returns `none`.
  -/
  getElem? : coll → idx → Option elem

  /--
  The syntax `arr[i]!` gets the `i`'th element of the collection `arr`,
  if it is present, and otherwise panics at runtime and returns the `default` term
  from `Inhabited elem`.
  -/
  getElem! [Inhabited elem] (xs : coll) (i : idx) : elem :=
    match getElem? xs i with | some e => e | none => outOfBounds
goal: coll → idx → Option elem

full_name: GetElem?.getElem!
code: @[inherit_doc GetElem]
class GetElem? (coll : Type u) (idx : Type v) (elem : outParam (Type w))
    (valid : outParam (coll → idx → Prop)) extends GetElem coll idx elem valid where
  /--
  The syntax `arr[i]?` gets the `i`'th element of the collection `arr`,
  if it is present (and wraps it in `some`), and otherwise returns `none`.
  -/
  getElem? : coll → idx → Option elem

  /--
  The syntax `arr[i]!` gets the `i`'th element of the collection `arr`,
  if it is present, and otherwise panics at runtime and returns the `default` term
  from `Inhabited elem`.
  -/
  getElem! [Inhabited elem] (xs : coll) (i : idx) : elem :=
    match getElem? xs i with | some e => e | none => outOfBounds
goal: elem

full_name: GetElem?
code: @[inherit_doc GetElem]
class GetElem? (coll : Type u) (idx : Type v) (elem : outParam (Type w))
    (valid : outParam (coll → idx → Prop)) extends GetElem coll idx elem valid where
  /--
  The syntax `arr[i]?` gets the `i`'th element of the collection `arr`,
  if it is present (and wraps it in `some`), and otherwise returns `none`.
  -/
  getElem? : coll → idx → Option elem

  /--
  The syntax `arr[i]!` gets the `i`'th element of the collection `arr`,
  if it is present, and otherwise panics at runtime and returns the `default` term
  from `Inhabited elem`.
  -/
  getElem! [Inhabited elem] (xs : coll) (i : idx) : elem :=
    match getElem? xs i with | some e => e | none => outOfBounds
goal: Type (max (max u v) w)

full_name: «term__[_]_?»
code: macro:max x:term noWs "[" i:term "]" noWs "?" : term => `(getElem? $x $i)
goal: Lean.TrailingParserDescr

full_name: «_aux_.lake_packages_lean4_src_lean_Init_GetElem___macroRules_term__[_]_?_1»
code: macro:max x:term noWs "[" i:term "]" noWs "?" : term => `(getElem? $x $i)
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_GetElem___macroRules_term__[_]_!_1»
code: macro:max x:term noWs "[" i:term "]" noWs "!" : term => `(getElem! $x $i)
goal: Lean.Macro

full_name: «term__[_]_!»
code: macro:max x:term noWs "[" i:term "]" noWs "!" : term => `(getElem! $x $i)
goal: Lean.TrailingParserDescr

full_name: instGetElem?OfGetElemOfDecidable
code: instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (valid xs i)] :
    GetElem? coll idx elem valid 
goal: GetElem? coll idx elem valid

full_name: LawfulGetElem
code: class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
   (dom : outParam (cont → idx → Prop)) [ge : GetElem? cont idx elem dom] : Prop where

  getElem?_def (c : cont) (i : idx) [Decidable (dom c i)] :
      c[i]? = if h : dom c i then some (c[i]'h) else none := by
    intros
    try simp only [getElem?] <;> congr
  getElem!_def [Inhabited elem] (c : cont) (i : idx) :
      c[i]! = match c[i]? with | some e => e | none => default := by
    intros
    simp only [getElem!, getElem?, outOfBounds_eq_default]
goal: Prop

full_name: LawfulGetElem.getElem!_def
code: class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
   (dom : outParam (cont → idx → Prop)) [ge : GetElem? cont idx elem dom] : Prop where

  getElem?_def (c : cont) (i : idx) [Decidable (dom c i)] :
      c[i]? = if h : dom c i then some (c[i]'h) else none := by
    intros
    try simp only [getElem?] <;> congr
  getElem!_def [Inhabited elem] (c : cont) (i : idx) :
      c[i]! = match c[i]? with | some e => e | none => default := by
    intros
    simp only [getElem!, getElem?, outOfBounds_eq_default]
goal: getElem! c i =
  match getElem? c i with
  | some e => e
  | none => default

full_name: LawfulGetElem.getElem?_def
code: class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
   (dom : outParam (cont → idx → Prop)) [ge : GetElem? cont idx elem dom] : Prop where

  getElem?_def (c : cont) (i : idx) [Decidable (dom c i)] :
      c[i]? = if h : dom c i then some (c[i]'h) else none := by
    intros
    try simp only [getElem?] <;> congr
  getElem!_def [Inhabited elem] (c : cont) (i : idx) :
      c[i]! = match c[i]? with | some e => e | none => default := by
    intros
    simp only [getElem!, getElem?, outOfBounds_eq_default]
goal: getElem? c i = if h : dom c i then some (getElem c i h) else none

full_name: instLawfulGetElem
code: instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (valid xs i)] :
    LawfulGetElem coll idx elem valid 
goal: LawfulGetElem coll idx elem valid

full_name: getElem?_pos
code: theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
    (c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] : c[i]? = some (c[i]'h) 
goal: getElem? c i = some (getElem c i h)

full_name: getElem?_neg
code: theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
    (c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]? = none 
goal: getElem? c i = none

full_name: getElem!_pos
code: theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
    [Inhabited elem] (c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] :
    c[i]! = c[i]'h 
goal: getElem! c i = getElem c i h

full_name: getElem!_neg
code: theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
    [Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]! = default 
goal: getElem! c i = default

full_name: Fin.instGetElemFinVal
code: instance instGetElemFinVal [GetElem cont Nat elem dom] : GetElem cont (Fin n) elem fun xs i => dom xs i 
goal: GetElem cont (Fin n) elem fun xs i => dom xs ↑i

full_name: Fin.instGetElem?FinVal
code: instance instGetElem?FinVal [GetElem? cont Nat elem dom] : GetElem? cont (Fin n) elem fun xs i => dom xs i 
goal: GetElem? cont (Fin n) elem fun xs i => dom xs ↑i

full_name: Fin.instLawfulGetElemValOfNat
code: instance [GetElem? cont Nat elem dom] [h : LawfulGetElem cont Nat elem dom] :
      LawfulGetElem cont (Fin n) elem fun xs i => dom xs i 
goal: LawfulGetElem cont (Fin n) elem fun xs i => dom xs ↑i

full_name: Fin.getElem_fin
code: @[simp] theorem getElem_fin [GetElem? Cont Nat Elem Dom] (a : Cont) (i : Fin n) (h : Dom a i) :
    a[i] = a[i.1] 
goal: getElem a i h = getElem a (↑i) h

full_name: Fin.getElem?_fin
code: @[simp] theorem getElem?_fin [h : GetElem? Cont Nat Elem Dom] (a : Cont) (i : Fin n)
    [Decidable (Dom a i)] : a[i]? = a[i.1]? 
goal: getElem? a i = getElem? a ↑i

full_name: Fin.getElem!_fin
code: @[simp] theorem getElem!_fin [GetElem? Cont Nat Elem Dom] (a : Cont) (i : Fin n)
    [Decidable (Dom a i)] [Inhabited Elem] : a[i]! = a[i.1]! 
goal: getElem! a i = getElem! a ↑i

full_name: Fin.«_aux_.lake_packages_lean4_src_lean_Init_GetElem___macroRules_tacticGet_elem_tactic_trivial_1»
code: macro_rules
  | `(tactic| get_elem_tactic_trivial) => `(tactic| apply Fin.val_lt_of_le; get_elem_tactic_trivial; done)
goal: Lean.Macro

full_name: List.instGetElemNatLtLength
code: instance : GetElem (List α) Nat α fun as i => i < as.length 
goal: GetElem (List α) Nat α fun as i => i < as.length

full_name: List.getElem_cons_zero
code: @[simp] theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a 
goal: getElem (a :: as) 0 h = a

full_name: List.cons_getElem_zero
code: @[deprecated (since := "2024-6-12")] abbrev cons_getElem_zero 
goal: getElem (a :: as) 0 h = a

full_name: List.getElem_cons_succ
code: @[simp] theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) 
goal: getElem (a :: as) (i + 1) h = getElem as i ⋯

full_name: List.cons_getElem_succ
code: @[deprecated (since := "2024-6-12")] abbrev cons_getElem_succ 
goal: getElem (a :: as) (i + 1) h = getElem as i ⋯

full_name: List.get_drop_eq_drop
code: theorem get_drop_eq_drop (as : List α) (i : Nat) (h : i < as.length) : as[i] :: as.drop (i+1) = as.drop i 
goal: getElem as i h :: List.drop (i + 1) as = List.drop i as

full_name: Array.instGetElemNatLtSize
code: instance : GetElem (Array α) Nat α fun xs i => i < xs.size 
goal: GetElem (Array α) Nat α fun xs i => i < xs.size

full_name: Lean.Syntax.instGetElemNatTrue
code: instance : GetElem Syntax Nat Syntax fun _ _ => True 
goal: GetElem Lean.Syntax Nat Lean.Syntax fun x x => True