Zulip Chat Archive

Stream: lean4

Topic: Trees in lean


Anton Mueller (Sep 01 2025 at 12:46):

I nede to work with trees as below, unfortunately i did not find them in mathlib like this. Initially i tried to work with a type DIR containing middle, left and right as its sole values and then defined paths as List Dir. The current approach looks better to me, no overhead with adding arguments on correctness of paths etc.

The problem is with the set function: I have to include a pattern, which is unreachable. The sensible approach, having the first line as _, base => T' is not accepted: "Dependent match elimination failed: Expected a constructor, but found the inaccessible pattern .(U)"

My question: Why does this not work, and where can i find implementations of trees which have comparable functionalities implemented, so that i can learn from these approaches?

Here an #mwe of what i have so far

set_option autoImplicit true

inductive Tree where
  | leaf (n : Nat)
  | scon (n : Nat) (T : Tree)
  | bcon (n  : Nat) (l r : Tree)
open Tree

inductive Path : Tree  Tree  Type
  | base  : Path t t
  | middle (p : Path t u) : Path (scon n t) u
  | left    (p : Path l u) : Path (bcon n l r) u
  | right  (p : Path r u) : Path (bcon n l r) u
open Path

def Tree.set (T : Tree) {U} (T' : Tree) (path : Path T U) : Tree :=
  match T, path with
    | leaf ann, base => T' -- why not _, base => T'
    | scon ann R, middle p => scon ann (set R T' p)
    | bcon ann l r, right p => bcon ann l (set r T' p)
    | bcon ann l r, left p => bcon ann (set l T' p) r
    | _, _ => T'

Kim Morrison (Sep 01 2025 at 12:56):

Did you see docs#Tree? This just sets the children to nil to represent your leaf or scon.

Damiano Testa (Sep 01 2025 at 13:02):

docs#Tree ? :slight_smile:

Robin Arnez (Sep 01 2025 at 13:28):

You can explicitly pull U into the match (which usually happens implicitly but it seems like at the wrong position):

inductive Tree where
  | leaf (n : Nat)
  | scon (n : Nat) (T : Tree)
  | bcon (n  : Nat) (l r : Tree)
open Tree

inductive Path : Tree  Tree  Type
  | base  : Path t t
  | middle (p : Path t u) : Path (scon n t) u
  | left    (p : Path l u) : Path (bcon n l r) u
  | right  (p : Path r u) : Path (bcon n l r) u

def Tree.set (T : Tree) {U} (T' : Tree) (path : Path T U) : Tree :=
  match T, U, path with
  | _, _, .base => T' -- why not _, base => T'
  | .scon ann R, _, .middle p => scon ann (set R T' p)
  | .bcon ann l r, _, .right p => bcon ann l (set r T' p)
  | .bcon ann l r, _, .left p => bcon ann (set l T' p) r

Why? idk

Anton Mueller (Sep 01 2025 at 13:30):

I already found docs#Tree, i did not find it particularly useful for my demands.

Concerning working with a more reduced set of constructors (i.e. deriving leaf and scon), but thought my approach to be more natural to deal with my problem.

What is missing from docs#Tree is just something that realizes pointers or something comparable, with which subtrees can be adressed and replaced (indexOf in ## Mathlib.Data.Tree.Get is the closest but totally not what i need)

Anton Mueller (Sep 01 2025 at 13:32):

Robin Arnez Great, thank you!


Last updated: Dec 20 2025 at 21:32 UTC