/- Copyright (c) 2024 François G. Dorais. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: François G. Dorais -/ module prelude import all Init.Data.List.OfFn public import Init.Data.List.Monadic public section set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables. set_option linter.indexVariables true -- Enforce naming conventions for index variables. namespace List /-- Lists all elements of `Fin n` in order, starting at `0`. Examples: * `List.finRange 0 = ([] : List (Fin 0))` * `List.finRange 2 = ([0, 1] : List (Fin 2))` -/ @[expose] def finRange (n : Nat) : List (Fin n) := ofFn fun i => i @[simp, grind =] theorem length_finRange {n : Nat} : (List.finRange n).length = n := by simp [List.finRange] @[simp, grind =] theorem getElem_finRange {i : Nat} (h : i < (List.finRange n).length) : (finRange n)[i] = Fin.cast length_finRange ⟨i, h⟩ := by simp [List.finRange] @[simp, grind =] theorem finRange_zero : finRange 0 = [] := by simp [finRange] theorem finRange_succ {n} : finRange (n+1) = 0 :: (finRange n).map Fin.succ := by apply List.ext_getElem; simp; intro i; cases i <;> simp theorem finRange_succ_last {n} : finRange (n+1) = (finRange n).map Fin.castSucc ++ [Fin.last n] := by apply List.ext_getElem · simp · intros simp only [List.finRange, List.getElem_ofFn, getElem_append, length_map, length_ofFn, getElem_map, Fin.castSucc_mk, getElem_singleton] split · rfl next h => exact Fin.eq_last_of_not_lt h @[grind _=_] theorem finRange_reverse {n} : (finRange n).reverse = (finRange n).map Fin.rev := by induction n with | zero => simp | succ n ih => conv => lhs; rw [finRange_succ_last] conv => rhs; rw [finRange_succ] rw [reverse_append, reverse_cons, reverse_nil, nil_append, singleton_append, ← map_reverse, map_cons, ih, map_map, map_map] congr 2; funext simp [Fin.rev_succ] @[simp, grind ←] theorem mem_finRange {n} (x : Fin n) : x ∈ finRange n := by simp [finRange] end List namespace Fin @[grind =] theorem foldlM_eq_foldlM_finRange [Monad m] (f : α → Fin n → m α) (x : α) : foldlM n f x = (List.finRange n).foldlM f x := by induction n generalizing x with | zero => simp | succ n ih => simp [foldlM_succ, List.finRange_succ, List.foldlM_cons] congr 1 funext y simp [ih, List.foldlM_map] @[grind =] theorem foldrM_eq_foldrM_finRange [Monad m] [LawfulMonad m] (f : Fin n → α → m α) (x : α) : foldrM n f x = (List.finRange n).foldrM f x := by induction n generalizing x with | zero => simp | succ n ih => simp [foldrM_succ, List.finRange_succ, ih, List.foldrM_map] @[grind =] theorem foldl_eq_finRange_foldl (f : α → Fin n → α) (x : α) : foldl n f x = (List.finRange n).foldl f x := by induction n generalizing x with | zero => simp | succ n ih => simp [foldl_succ, List.finRange_succ, ih, List.foldl_map] @[grind =] theorem foldr_eq_finRange_foldr (f : Fin n → α → α) (x : α) : foldr n f x = (List.finRange n).foldr f x := by induction n generalizing x with | zero => simp | succ n ih => simp [foldr_succ, List.finRange_succ, ih, List.foldr_map] end Fin namespace List theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} : ofFnM f = (do let a ← f 0 let as ← ofFnM fun i => f i.succ pure (a :: as)) := by simp [ofFnM, Fin.foldlM_eq_foldlM_finRange, List.finRange_succ, List.foldlM_cons_eq_append, List.foldlM_map] end List