This PR renames the namespace `Std.Range` to `Std.Legacy.Range`. Instead of using `Std.Range` and `[a:b]` notation, the new range type `Std.Rco` and its corresponding `a...b` notation should be used. There are also other ranges with open/closed/infinite boundary shapes in `Std.Data.Range.Polymorphic` and the new range notation also works for `Int`, `Int8`, `UInt8`, `Fin` etc.
89 lines
3.1 KiB
Text
89 lines
3.1 KiB
Text
/-
|
|
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
module
|
|
|
|
prelude
|
|
public import Init.Omega
|
|
|
|
public section
|
|
|
|
namespace Std.Legacy
|
|
-- We put `Range` in `Init` because we want the notation `[i:j]` without importing `Std`
|
|
-- We don't put `Range` in the top-level namespace to avoid collisions with user defined types
|
|
structure Range where
|
|
start : Nat := 0
|
|
stop : Nat
|
|
step : Nat := 1
|
|
step_pos : 0 < step
|
|
|
|
instance : Membership Nat Range where
|
|
mem r i := r.start ≤ i ∧ i < r.stop ∧ (i - r.start) % r.step = 0
|
|
|
|
namespace Range
|
|
universe u v
|
|
|
|
/-- The number of elements in the range. -/
|
|
@[simp, expose] def size (r : Range) : Nat := (r.stop - r.start + r.step - 1) / r.step
|
|
|
|
@[inline] protected def forIn' [Monad m] (range : Range) (init : β)
|
|
(f : (i : Nat) → i ∈ range → β → m (ForInStep β)) : m β :=
|
|
let rec @[specialize] loop (b : β) (i : Nat)
|
|
(hs : (i - range.start) % range.step = 0) (hl : range.start ≤ i := by omega) : m β := do
|
|
if h : i < range.stop then
|
|
match (← f i ⟨hl, by omega, hs⟩ b) with
|
|
| .done b => pure b
|
|
| .yield b =>
|
|
have := range.step_pos
|
|
loop b (i + range.step) (by rwa [Nat.add_comm, Nat.add_sub_assoc hl, Nat.add_mod_left])
|
|
else
|
|
pure b
|
|
have := range.step_pos
|
|
loop init range.start (by simp)
|
|
|
|
instance [Monad m] : ForIn' m Range Nat inferInstance where
|
|
forIn' := Range.forIn'
|
|
|
|
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
|
|
|
@[inline] protected def forM [Monad m] (range : Range) (f : Nat → m PUnit) : m PUnit :=
|
|
let rec @[specialize] loop (i : Nat): m PUnit := do
|
|
if i < range.stop then
|
|
f i
|
|
have := range.step_pos
|
|
loop (i + range.step)
|
|
else
|
|
pure ⟨⟩
|
|
have := range.step_pos
|
|
loop range.start
|
|
|
|
instance [Monad m] : ForM m Range Nat where
|
|
forM := Range.forM
|
|
|
|
syntax:max "[" withoutPosition(":" term) "]" : term
|
|
syntax:max "[" withoutPosition(term ":" term) "]" : term
|
|
syntax:max "[" withoutPosition(":" term ":" term) "]" : term
|
|
syntax:max "[" withoutPosition(term ":" term ":" term) "]" : term
|
|
|
|
macro_rules
|
|
| `([ : $stop]) => `({ stop := $stop, step_pos := Nat.zero_lt_one : Range })
|
|
| `([ $start : $stop ]) => `({ start := $start, stop := $stop, step_pos := Nat.zero_lt_one : Range })
|
|
| `([ $start : $stop : $step ]) => `({ start := $start, stop := $stop, step := $step, step_pos := by decide : Range })
|
|
| `([ : $stop : $step ]) => `({ stop := $stop, step := $step, step_pos := by decide : Range })
|
|
|
|
end Range
|
|
end Std.Legacy
|
|
|
|
theorem Membership.mem.upper {i : Nat} {r : Std.Legacy.Range} (h : i ∈ r) : i < r.stop := h.2.1
|
|
|
|
theorem Membership.mem.lower {i : Nat} {r : Std.Legacy.Range} (h : i ∈ r) : r.start ≤ i := h.1
|
|
|
|
theorem Membership.mem.step {i : Nat} {r : Std.Legacy.Range} (h : i ∈ r) : (i - r.start) % r.step = 0 := h.2.2
|
|
|
|
theorem Membership.get_elem_helper {i n : Nat} {r : Std.Legacy.Range} (h₁ : i ∈ r) (h₂ : r.stop = n) :
|
|
i < n := h₂ ▸ h₁.2.1
|
|
|
|
macro_rules
|
|
| `(tactic| get_elem_tactic_extensible) => `(tactic| apply Membership.get_elem_helper; assumption; rfl)
|