101 lines
2.7 KiB
Text
101 lines
2.7 KiB
Text
|
|
/-! # Nested inductive types
|
|
|
|
See "Recursion through lists and arrays" in https://blog.lean-lang.org/blog/2024-9-1-lean-4110/
|
|
|
|
This test file exercises the `attach`/`unattach` API.
|
|
-/
|
|
|
|
namespace List
|
|
|
|
inductive Tree where | node : List Tree → Tree
|
|
|
|
namespace Tree
|
|
|
|
def rev : Tree → Tree
|
|
| node ts => .node (ts.attach.reverse.map (fun ⟨t, _⟩ => t.rev))
|
|
|
|
-- Note that `simp` now automatically removes the `attach`.
|
|
@[simp] theorem rev_def (ts : List Tree) :
|
|
Tree.rev (.node ts) = .node (ts.reverse.map rev) := by
|
|
simp [Tree.rev]
|
|
|
|
-- Variant with an explicit `have`, rather than using a pattern match.
|
|
def rev' : Tree → Tree
|
|
| node ts => .node (ts.attach.reverse.map (fun t => have := t.2; t.1.rev'))
|
|
|
|
@[simp] theorem rev'_def (ts : List Tree) :
|
|
Tree.rev' (.node ts) = .node (ts.reverse.map rev') := by
|
|
simp [Tree.rev']
|
|
|
|
/-- Define `size` using a `foldl` over `attach`. -/
|
|
def size : Tree → Nat
|
|
| node ts => 1 + ts.attach.foldl (fun acc ⟨t, _⟩ => acc + t.size) 0
|
|
|
|
@[simp] theorem size_def (ts : List Tree) :
|
|
size (.node ts) = 1 + ts.foldl (fun acc t => acc + t.size) 0 := by
|
|
simp [size]
|
|
|
|
/-- Define `depth` using a `foldr` over `attach`. -/
|
|
def depth : Tree → Nat
|
|
| node ts => 1 + ts.attach.foldr (fun ⟨t, _⟩ acc => acc + t.depth) 0
|
|
|
|
@[simp] theorem depth_def (ts : List Tree) :
|
|
depth (.node ts) = 1 + ts.foldr (fun t acc => acc + t.depth) 0 := by
|
|
simp [depth]
|
|
|
|
end Tree
|
|
|
|
end List
|
|
|
|
namespace Array
|
|
|
|
inductive Tree where | node : Array Tree → Tree
|
|
|
|
namespace Tree
|
|
|
|
def rev : Tree → Tree
|
|
| node ts => .node (ts.attach.reverse.map (fun ⟨t, _⟩ => t.rev))
|
|
|
|
-- Note that `simp` now automatically removes the `attach`.
|
|
@[simp] theorem rev_def (ts : Array Tree) :
|
|
Tree.rev (.node ts) = .node (ts.reverse.map rev) := by
|
|
simp [Tree.rev]
|
|
|
|
/-- Define `size` using a `foldl` over `attach`. -/
|
|
def size : Tree → Nat
|
|
| node ts => 1 + ts.attach.foldl (fun acc ⟨t, _⟩ => acc + t.size) 0
|
|
|
|
@[simp] theorem size_def (ts : Array Tree) :
|
|
size (.node ts) = 1 + ts.foldl (fun acc t => acc + t.size) 0 := by
|
|
simp [size]
|
|
|
|
/-- Define `depth` using a `foldr` over `attach`. -/
|
|
def depth : Tree → Nat
|
|
| node ts => 1 + ts.attach.foldr (fun ⟨t, _⟩ acc => acc + t.depth) 0
|
|
|
|
@[simp] theorem depth_def (ts : Array Tree) :
|
|
depth (.node ts) = 1 + ts.foldr (fun t acc => acc + t.depth) 0 := by
|
|
simp [depth]
|
|
|
|
end Tree
|
|
|
|
end Array
|
|
|
|
|
|
namespace Option
|
|
|
|
inductive Tree where | node : Option Tree → Option Tree → Tree
|
|
|
|
namespace Tree
|
|
|
|
def rev : Tree → Tree
|
|
| node l r => .node (r.attach.map fun ⟨r, _⟩ => r.rev) (l.attach.map fun ⟨l, _⟩ => l.rev)
|
|
|
|
@[simp] theorem rev_def (l r : Option Tree) :
|
|
Tree.rev (.node l r) = .node (r.map rev) (l.map rev) := by
|
|
simp [Tree.rev]
|
|
|
|
end Tree
|
|
|
|
end Option
|