Documentation

Std.Do.Triple.SpecLemmas

Hoare triple specifications for select functions #

This module contains Hoare triple specifications for some functions in Core.

@[reducible, inline]
Equations
Instances For
    structure List.Cursor {α : Type u} (l : List α) :
    Instances For
      theorem List.Cursor.ext {α : Type u} {l : List α} {x y : l.Cursor} («prefix» : x.prefix = y.prefix) (suffix : x.suffix = y.suffix) :
      x = y
      theorem List.Cursor.ext_iff {α : Type u} {l : List α} {x y : l.Cursor} :
      def List.Cursor.at {α : Type u_1} (l : List α) (n : Nat) :
      Equations
      Instances For
        @[reducible, inline]
        abbrev List.Cursor.begin {α : Type u_1} (l : List α) :
        Equations
        Instances For
          @[reducible, inline]
          abbrev List.Cursor.end {α : Type u_1} (l : List α) :
          Equations
          Instances For
            def List.Cursor.current {α : Type u_1} {l : List α} (c : l.Cursor) (h : 0 < c.suffix.length := by get_elem_tactic) :
            α
            Equations
            Instances For
              def List.Cursor.tail {α✝ : Type u_1} {l : List α✝} (s : l.Cursor) (h : 0 < s.suffix.length := by get_elem_tactic) :
              Equations
              Instances For
                @[simp]
                theorem List.Cursor.prefix_at {α : Type u_1} {n : Nat} (l : List α) :
                («at» l n).prefix = take n l
                @[simp]
                theorem List.Cursor.suffix_at {α : Type u_1} {n : Nat} (l : List α) :
                («at» l n).suffix = drop n l
                @[simp]
                theorem List.Cursor.current_at {α : Type u_1} {n : Nat} (l : List α) (h : n < l.length) :
                («at» l n).current ⋯ = l[n]
                @[simp]
                theorem List.Cursor.tail_at {α : Type u_1} {n : Nat} (l : List α) (h : n < l.length) :
                («at» l n).tail ⋯ = «at» l (n + 1)
                theorem List.eq_of_range'_eq_append_cons {s n step : Nat} {xs : List Nat} {cur : Nat} {ys : List Nat} (h : range' s n step = xs ++ cur :: ys) :
                cur = s + step * xs.length
                theorem List.length_of_range'_eq_append_cons {s n step : Nat} {xs : List Nat} {cur : Nat} {ys : List Nat} (h : range' s n step = xs ++ cur :: ys) :
                n = xs.length + ys.length + 1
                theorem List.mem_of_range'_eq_append_cons {s n step : Nat} {xs : List Nat} {i : Nat} {ys : List Nat} (h : range' s n step = xs ++ i :: ys) :
                i ∈ range' s n step
                theorem List.gt_of_range'_eq_append_cons {s n step : Nat} {xs : List Nat} {i : Nat} {ys : List Nat} {j : Nat} (h : range' s n step = xs ++ i :: ys) (hstep : 0 < step) (hj : j ∈ xs) :
                j < i
                theorem List.lt_of_range'_eq_append_cons {s n step : Nat} {xs : List Nat} {i : Nat} {ys : List Nat} {j : Nat} (h : range' s n step = xs ++ i :: ys) (hstep : 0 < step) (hj : j ∈ ys) :
                i < j

                Monad #

                theorem Std.Do.Spec.pure' {m : Type u → Type v} {ps : PostShape} {α : Type u} {a : α} [Monad m] [WPMonad m ps] {P : Assertion ps} {Q : PostCond α ps} (h : P ⊢ₛ Q.fst a) :
                theorem Std.Do.Spec.pure {m : Type u → Type v} {ps : PostShape} [Monad m] [WPMonad m ps] {α : Type u} {a : α} {Q : PostCond α ps} :
                theorem Std.Do.Spec.bind' {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {x : m α} {f : α → m β} {P : Assertion ps} {Q : PostCond β ps} (h : ⦃P⦄ x ⦃(fun (a : α) => wp⟦f a⟧ Q, Q.snd)⦄) :
                ⦃P⦄ (x >>= f) ⦃Q⦄
                theorem Std.Do.Spec.bind {m : Type u → Type v} {ps : PostShape} [Monad m] [WPMonad m ps] {α β : Type u} {x : m α} {f : α → m β} {Q : PostCond β ps} :
                ⦃wp⟦x⟧ (fun (a : α) => wp⟦f a⟧ Q, Q.snd)⦄ (x >>= f) ⦃Q⦄
                theorem Std.Do.Spec.map {m : Type u → Type v} {ps : PostShape} [Monad m] [WPMonad m ps] {α β : Type u} {x : m α} {f : α → β} {Q : PostCond β ps} :
                ⦃wp⟦x⟧ (fun (a : α) => Q.fst (f a), Q.snd)⦄ (f <$> x) ⦃Q⦄
                theorem Std.Do.Spec.seq {m : Type u → Type v} {ps : PostShape} [Monad m] [WPMonad m ps] {α β : Type u} {x : m (α → β)} {y : m α} {Q : PostCond β ps} :
                ⦃wp⟦x⟧ (fun (f : α → β) => wp⟦y⟧ (fun (a : α) => Q.fst (f a), Q.snd), Q.snd)⦄ (x <*> y) ⦃Q⦄

                MonadLift #

                theorem Std.Do.Spec.monadLift_StateT {m : Type u → Type v} {ps : PostShape} {α σ : Type u} [Monad m] [WPMonad m ps] (x : m α) (Q : PostCond α (PostShape.arg σ ps)) :
                ⦃fun (s : σ) => wp⟦x⟧ (fun (a : α) => Q.fst a s, Q.snd)⦄ MonadLift.monadLift x ⦃Q⦄
                theorem Std.Do.Spec.monadLift_ReaderT {m : Type u → Type v} {ps : PostShape} {α ρ : Type u} [Monad m] [WPMonad m ps] (x : m α) (Q : PostCond α (PostShape.arg ρ ps)) :
                ⦃fun (s : ρ) => wp⟦x⟧ (fun (a : α) => Q.fst a s, Q.snd)⦄ MonadLift.monadLift x ⦃Q⦄
                theorem Std.Do.Spec.monadLift_ExceptT {m : Type u → Type v} {ps : PostShape} {α ε : Type u} [Monad m] [WPMonad m ps] (x : m α) (Q : PostCond α (PostShape.except ε ps)) :

                MonadLiftT #

                MonadFunctor #

                theorem Std.Do.Spec.monadMap_StateT {m : Type u → Type v} {ps : PostShape} {σ : Type u} [Monad m] [WP m ps] (f : {β : Type u} → m β → m β) {α : Type u} (x : StateT σ m α) (Q : PostCond α (PostShape.arg σ ps)) :
                ⦃fun (s : σ) => wp⟦f (x.run s)⟧ (fun (x : α × σ) => match x with | (a, s) => Q.fst a s, Q.snd)⦄ MonadFunctor.monadMap (fun {β : Type u} => f) x ⦃Q⦄
                theorem Std.Do.Spec.monadMap_ReaderT {m : Type u → Type v} {ps : PostShape} {ρ : Type u} [Monad m] [WP m ps] (f : {β : Type u} → m β → m β) {α : Type u} (x : ReaderT ρ m α) (Q : PostCond α (PostShape.arg ρ ps)) :
                ⦃fun (s : ρ) => wp⟦f (x.run s)⟧ (fun (a : α) => Q.fst a s, Q.snd)⦄ MonadFunctor.monadMap (fun {β : Type u} => f) x ⦃Q⦄
                theorem Std.Do.Spec.monadMap_ExceptT {m : Type u → Type v} {ps : PostShape} {ε : Type u} [Monad m] [WP m ps] (f : {β : Type u} → m β → m β) {α : Type u} (x : ExceptT ε m α) (Q : PostCond α (PostShape.except ε ps)) :
                ⦃wp⟦f x.run⟧ (fun (x : Except ε α) => match x with | Except.ok a => Q.fst a | Except.error e => Q.snd.fst e, Q.snd.snd)⦄ MonadFunctor.monadMap (fun {β : Type u} => f) x ⦃Q⦄

                MonadFunctorT #

                theorem Std.Do.Spec.monadMap_trans {m : Type u → Type v} {ps : PostShape} {o : Type u → Type u_1} {n : Type u → Type u_2} {α : Type u} {f : {β : Type u} → m β → m β} {x : o α} {Q : PostCond α ps} [WP o ps] [MonadFunctor n o] [MonadFunctorT m n] :
                ⦃wp⟦MonadFunctor.monadMap (fun {β : Type u} => monadMap fun {β : Type u} => f) x⟧ Q⦄ monadMap f x ⦃Q⦄
                theorem Std.Do.Spec.monadMap_refl {m : Type u → Type v} {ps : PostShape} {α : Type u} {f : {β : Type u} → m β → m β} {x : m α} {Q : PostCond α ps} [WP m ps] :

                ReaderT #

                theorem Std.Do.Spec.read_ReaderT {m : Type u → Type v} {psm : PostShape} {ρ : Type u} {Q : PostCond ρ (PostShape.arg ρ psm)} [Monad m] [WPMonad m psm] :
                theorem Std.Do.Spec.withReader_ReaderT {m : Type u → Type v} {psm : PostShape} {ρ α : Type u} {f : ρ → ρ} {x : ReaderT ρ m α} {Q : PostCond α (PostShape.arg ρ psm)} [Monad m] [WPMonad m psm] :
                ⦃fun (r : ρ) => wp⟦x⟧ (fun (a : α) (x : ρ) => Q.fst a r, Q.snd) (f r)⦄ MonadWithReaderOf.withReader f x ⦃Q⦄

                StateT #

                theorem Std.Do.Spec.get_StateT {m : Type u → Type v} {psm : PostShape} {σ : Type u} {Q : PostCond σ (PostShape.arg σ psm)} [Monad m] [WPMonad m psm] :
                theorem Std.Do.Spec.set_StateT {m : Type u → Type v} {psm : PostShape} {σ : Type u} {s : σ} {Q : PostCond PUnit (PostShape.arg σ psm)} [Monad m] [WPMonad m psm] :
                theorem Std.Do.Spec.modifyGet_StateT {m : Type u → Type v} {ps : PostShape} {σ α : Type u} {f : σ → α × σ} {Q : PostCond α (PostShape.arg σ ps)} [Monad m] [WPMonad m ps] :
                ⦃fun (s : σ) => have t := f s; Q.fst t.fst t.snd⦄ MonadStateOf.modifyGet f ⦃Q⦄

                ExceptT #

                theorem Std.Do.Spec.run_ExceptT {m : Type u → Type v} {ps : PostShape} {ε α : Type u} {Q : PostCond (Except ε α) ps} [WP m ps] (x : ExceptT ε m α) :
                ⦃wp⟦x⟧ (fun (a : α) => Q.fst (Except.ok a), fun (e : ε) => Q.fst (Except.error e), Q.snd)⦄ x.run ⦃Q⦄
                theorem Std.Do.Spec.throw_ExceptT {m : Type u → Type v} {ps : PostShape} {ε α : Type u} {e : ε} {Q : PostCond α (PostShape.except ε ps)} [Monad m] [WPMonad m ps] :
                theorem Std.Do.Spec.tryCatch_ExceptT {m : Type u → Type v} {ps : PostShape} {α ε : Type u} {x : ExceptT ε m α} {h : ε → ExceptT ε m α} [Monad m] [WPMonad m ps] (Q : PostCond α (PostShape.except ε ps)) :

                Except #

                theorem Std.Do.Spec.throw_Except {m : Type u → Type v} {ps : PostShape} {ε α : Type u_1} {e : ε} {Q : PostCond α (PostShape.except ε PostShape.pure)} [Monad m] [WPMonad m ps] :
                theorem Std.Do.Spec.tryCatch_Except {α ε : Type u_1} {x : Except ε α} {h : ε → Except ε α} (Q : PostCond α (PostShape.except ε PostShape.pure)) :

                EStateM #

                theorem Std.Do.Spec.modifyGet_EStateM {ε σ α : Type u_1} {f : σ → α × σ} {Q : PostCond α (PostShape.except ε (PostShape.arg σ PostShape.pure))} :
                ⦃fun (s : σ) => have t := f s; Q.fst t.fst t.snd⦄ MonadStateOf.modifyGet f ⦃Q⦄
                theorem Std.Do.Spec.tryCatch_EStateM {α ε σ : Type u_1} {x : EStateM ε σ α} {h : ε → EStateM ε σ α} (Q : PostCond α (PostShape.except ε (PostShape.arg σ PostShape.pure))) :

                Lifting MonadStateOf #

                Lifting MonadReaderOf #

                Lifting MonadExceptOf #

                theorem Std.Do.Spec.throw_MonadExcept {m : Type u → Type v} {ε : Type u_1} {α : Type u} {e : ε} {ps✝ : PostShape} {Q : PostCond α ps✝} [MonadExceptOf ε m] [WP m ps✝] :
                theorem Std.Do.Spec.tryCatch_MonadExcept {m : Type u → Type v} {ps : PostShape} {ε : Type u_1} {α : Type u} {x : m α} {h : ε → m α} [MonadExceptOf ε m] [WP m ps] (Q : PostCond α ps) :
                theorem Std.Do.Spec.throw_ReaderT {m : Type u → Type v} {sh : PostShape} {ε : Type u_1} {ρ α : Type u} {e : ε} {Q : PostCond α (PostShape.arg ρ sh)} [WP m sh] [Monad m] [MonadExceptOf ε m] :
                theorem Std.Do.Spec.throw_StateT {m : Type u → Type v} {ps : PostShape} {ε : Type u_1} {α σ : Type u} {e : ε} [WP m ps] [Monad m] [MonadExceptOf ε m] (Q : PostCond α (PostShape.arg σ ps)) :
                theorem Std.Do.Spec.throw_ExceptT_lift {m : Type u → Type v} {ps : PostShape} {ε α ε' : Type u} {e : ε} [WP m ps] [Monad m] [MonadExceptOf ε m] (Q : PostCond α (PostShape.except ε' ps)) :
                ⦃wp⟦MonadExceptOf.throw e⟧ (fun (x : Except ε' α) => match x with | Except.ok a => Q.fst a | Except.error e => Q.snd.fst e, Q.snd.snd)⦄ MonadExceptOf.throw e ⦃Q⦄
                theorem Std.Do.Spec.tryCatch_ReaderT {m : Type u → Type v} {ps : PostShape} {ε : Type u_1} {α ρ : Type u} {x : ReaderT ρ m α} {h : ε → ReaderT ρ m α} [WP m ps] [Monad m] [MonadExceptOf ε m] (Q : PostCond α (PostShape.arg ρ ps)) :
                ⦃fun (r : ρ) => wp⟦MonadExceptOf.tryCatch (x.run r) fun (e : ε) => (h e).run r⟧ (fun (a : α) => Q.fst a r, Q.snd)⦄ MonadExceptOf.tryCatch x h ⦃Q⦄
                theorem Std.Do.Spec.tryCatch_StateT {m : Type u → Type v} {ps : PostShape} {ε : Type u_1} {α σ : Type u} {x : StateT σ m α} {h : ε → StateT σ m α} [WP m ps] [Monad m] [MonadExceptOf ε m] (Q : PostCond α (PostShape.arg σ ps)) :
                ⦃fun (s : σ) => wp⟦MonadExceptOf.tryCatch (x.run s) fun (e : ε) => (h e).run s⟧ (fun (xs : α × σ) => Q.fst xs.fst xs.snd, Q.snd)⦄ MonadExceptOf.tryCatch x h ⦃Q⦄
                theorem Std.Do.Spec.tryCatch_ExceptT_lift {m : Type u → Type v} {ps : PostShape} {ε α ε' : Type u} {x : ExceptT ε' m α} {h : ε → ExceptT ε' m α} [WP m ps] [Monad m] [MonadExceptOf ε m] (Q : PostCond α (PostShape.except ε' ps)) :
                ⦃wp⟦MonadExceptOf.tryCatch x h⟧ (fun (x : Except ε' α) => match x with | Except.ok a => Q.fst a | Except.error e => Q.snd.fst e, Q.snd.snd)⦄ MonadExceptOf.tryCatch x h ⦃Q⦄

                ForIn #

                @[reducible, inline]
                abbrev Std.Do.Invariant {α : Type u} (xs : List α) (β : Type u) (ps : PostShape) :

                The type of loop invariants used by the specifications of for ... in ... loops. A loop invariant is a PostCond that takes as parameters

                • A List.Cursor xs representing the iteration state of the loop. It is parameterized by the list of elements xs that the for loop iterates over.
                • A state tuple of type β, which will be a nesting of MProds representing the elaboration of let mut variables and early return.

                The loop specification lemmas will use this in the following way: Before entering the loop, the zipper's prefix is empty and the suffix is xs. After leaving the loop, the zipper's suffix is empty and the prefix is xs. During the induction step, the invariant holds for a suffix with head element x. After running the loop body, the invariant then holds after shifting x to the prefix.

                Equations
                Instances For
                  @[reducible, inline]
                  abbrev Std.Do.Invariant.withEarlyReturn {ps : PostShape} {α✝ : Type u} {xs : List α✝} {β γ : Type u} (onContinue : xs.Cursor → β → Assertion ps) (onReturn : γ → β → Assertion ps) (onExcept : ExceptConds ps := ExceptConds.false) :
                  Invariant xs (MProd (Option γ) β) ps

                  Helper definition for specifying loop invariants for loops with early return.

                  for ... in ... loops with early return of type γ elaborate to a call like this:

                  forIn (β := MProd (Option γ) ...) (b := ⟨none, ...⟩) collection loopBody
                  

                  Note that the first component of the MProd state tuple is the optional early return value. It is none as long as there was no early return and some r if the loop returned early with r.

                  This function allows to specify different invariants for the loop body depending on whether the loop terminated early or not. When there was an early return, the loop has effectively finished, which is encoded by the additional ⌜xs.suffix = []⌝ assertion in the invariant. This assertion is vital for successfully proving the induction step, as it contradicts with the assumption that xs.suffix = x::rest of the inductive hypothesis at the start of the loop body, meaning that users won't need to prove anything about the bogus case where the loop has returned early yet takes another iteration of the loop body.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    theorem Std.Do.Spec.forIn'_list {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : List α} {init : β} {f : (a : α) → a ∈ xs → β → m (ForInStep β)} (inv : Invariant xs β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur ⋯ b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs, property := ⋯ }, init)⦄ forIn' xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.forIn'_list_const_inv {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : List α} {init : β} {f : (a : α) → a ∈ xs → β → m (ForInStep β)} {inv : PostCond β ps} (step : ∀ (x : α) (hx : x ∈ xs) (b : β), ⦃inv.fst b⦄ f x hx b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst b' | ForInStep.done b' => inv.fst b', inv.snd)⦄) :
                    ⦃inv.fst init⦄ forIn' xs init f ⦃inv⦄
                    theorem Std.Do.Spec.forIn_list {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : List α} {init : β} {f : α → β → m (ForInStep β)} (inv : Invariant xs β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs, property := ⋯ }, init)⦄ forIn xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.forIn_list_const_inv {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : List α} {init : β} {f : α → β → m (ForInStep β)} {inv : PostCond β ps} (step : ∀ (hd : α) (b : β), ⦃inv.fst b⦄ f hd b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst b' | ForInStep.done b' => inv.fst b', inv.snd)⦄) :
                    ⦃inv.fst init⦄ forIn xs init f ⦃inv⦄
                    theorem Std.Do.Spec.foldlM_list {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : List α} {init : β} {f : β → α → m β} (inv : Invariant xs β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f b cur ⦃(fun (b' : β) => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs, property := ⋯ }, init)⦄ List.foldlM f init xs ⦃(fun (b : β) => inv.fst ({ «prefix» := xs, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.foldlM_list_const_inv {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : List α} {init : β} {f : β → α → m β} {inv : PostCond β ps} (step : ∀ (hd : α) (b : β), ⦃inv.fst b⦄ f b hd ⦃(fun (b' : β) => inv.fst b', inv.snd)⦄) :
                    ⦃inv.fst init⦄ List.foldlM f init xs ⦃inv⦄
                    theorem Std.Do.Spec.forIn'_range {β : Type} {m : Type → Type v} {ps : PostShape} [Monad m] [WPMonad m ps] {xs : Range} {init : β} {f : (a : Nat) → a ∈ xs → β → m (ForInStep β)} (inv : Invariant xs.toList β ps) (step : ∀ (pref : List Nat) (cur : Nat) (suff : List Nat) (h : xs.toList = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur ⋯ b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs.toList, property := ⋯ }, init)⦄ forIn' xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.forIn_range {β : Type} {m : Type → Type v} {ps : PostShape} [Monad m] [WPMonad m ps] {xs : Range} {init : β} {f : Nat → β → m (ForInStep β)} (inv : Invariant xs.toList β ps) (step : ∀ (pref : List Nat) (cur : Nat) (suff : List Nat) (h : xs.toList = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs.toList, property := ⋯ }, init)⦄ forIn xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.forIn'_prange {m : Type u → Type v} {ps : PostShape} {su sl : PRange.BoundShape} {α β : Type u} [Monad m] [WPMonad m ps] [PRange.UpwardEnumerable α] [PRange.SupportsUpperBound su α] [PRange.SupportsLowerBound sl α] [PRange.HasFiniteRanges su α] [PRange.BoundedUpwardEnumerable sl α] [PRange.LawfulUpwardEnumerable α] [PRange.LawfulUpwardEnumerableLowerBound sl α] [PRange.LawfulUpwardEnumerableUpperBound su α] {xs : PRange { lower := sl, upper := su } α} {init : β} {f : (a : α) → a ∈ xs → β → m (ForInStep β)} (inv : Invariant xs.toList β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs.toList = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur ⋯ b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs.toList, property := ⋯ }, init)⦄ forIn' xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.forIn_prange {m : Type u → Type v} {ps : PostShape} {su sl : PRange.BoundShape} {α β : Type u} [Monad m] [WPMonad m ps] [PRange.UpwardEnumerable α] [PRange.SupportsUpperBound su α] [PRange.SupportsLowerBound sl α] [PRange.HasFiniteRanges su α] [PRange.BoundedUpwardEnumerable sl α] [PRange.LawfulUpwardEnumerable α] [PRange.LawfulUpwardEnumerableLowerBound sl α] [PRange.LawfulUpwardEnumerableUpperBound su α] {xs : PRange { lower := sl, upper := su } α} {init : β} {f : α → β → m (ForInStep β)} (inv : Invariant xs.toList β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs.toList = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs.toList, property := ⋯ }, init)⦄ forIn xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.forIn'_array {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : Array α} {init : β} {f : (a : α) → a ∈ xs → β → m (ForInStep β)} (inv : Invariant xs.toList β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs.toList = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur ⋯ b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs.toList, property := ⋯ }, init)⦄ forIn' xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.forIn_array {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : Array α} {init : β} {f : α → β → m (ForInStep β)} (inv : Invariant xs.toList β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs.toList = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f cur b ⦃(fun (r : ForInStep β) => match r with | ForInStep.yield b' => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b') | ForInStep.done b' => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs.toList, property := ⋯ }, init)⦄ forIn xs init f ⦃(fun (b : β) => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b), inv.snd)⦄
                    theorem Std.Do.Spec.foldlM_array {m : Type u → Type v} {ps : PostShape} {α β : Type u} [Monad m] [WPMonad m ps] {xs : Array α} {init : β} {f : β → α → m β} (inv : Invariant xs.toList β ps) (step : ∀ (pref : List α) (cur : α) (suff : List α) (h : xs.toList = pref ++ cur :: suff) (b : β), ⦃inv.fst ({ «prefix» := pref, suffix := cur :: suff, property := ⋯ }, b)⦄ f b cur ⦃(fun (b' : β) => inv.fst ({ «prefix» := pref ++ [cur], suffix := suff, property := ⋯ }, b'), inv.snd)⦄) :
                    ⦃inv.fst ({ «prefix» := [], suffix := xs.toList, property := ⋯ }, init)⦄ Array.foldlM f init xs ⦃(fun (b : β) => inv.fst ({ «prefix» := xs.toList, suffix := [], property := ⋯ }, b), inv.snd)⦄