Zulip Chat Archive
Stream: new members
Topic: Huffman Tree
Sébastien Boisgérault (Jan 05 2026 at 10:05):
Hello everyone,
Is the following code (that Lean 4 rejects) "patchable" or is there a fundamental limitation there that I should know about? If that's the case, what would be the idiomatic way to define a tree where only the terminal leaves can carry a (String) payload?
inductive Tree where
| nil : Tree
| leaf
(string? : Option String)
(left : Tree)
(right : Tree)
(check : string?.isSome → (left = Tree.nil) ∧ (right = Tree.nil)) :
Tree
Sébastien Boisgérault (Jan 05 2026 at 10:07):
FYI, the top-level error is:
(kernel) invalid nested inductive datatype 'And', nested inductive datatypes parameters cannot contain local variables.
Damiano Testa (Jan 05 2026 at 10:17):
Would what is below work for you?
inductive Tree where
| leaf (s : String) : Tree
| node (left right : Tree) : Tree
Eric Wieser (Jan 05 2026 at 10:18):
Or if you also want the string to be optional on leaf nodes (as in your original)
inductive Tree where
| nil : Tree
| leaf (s : String) : Tree
| node (left right : Tree) : Tree
or more simply
inductive Tree where
| leaf (s : Option String) : Tree
| node (left right : Tree) : Tree
Sébastien Boisgérault (Jan 05 2026 at 11:08):
Damiano Testa said:
Would what is below work for you?
inductive Tree where | leaf (s : String) : Tree | node (left right : Tree) : Tree
In this model, you cannot have a leaf that has a single non-nil child right? A tree that has for example a single "left" leave that holds a String should be valid.
Damiano Testa (Jan 05 2026 at 11:17):
Yes, the model that I suggested does not allow what you want. But Eric's seems to:
inductive Tree where
| nil : Tree
| leaf (s : String) : Tree
| node (left right : Tree) : Tree
#check Tree.node (Tree.leaf "") Tree.nil
Sébastien Boisgérault (Jan 05 2026 at 11:17):
I think that there are two issues here:
- I have not really thought about the existence of a simple "classic" ADT model, correct by construction for my context, thank you for pushing me to revisit this. :pray:
- But I was also a little surprised for not being able to simply embed extra constraints in the definition of inductive types, since when I do that with structs, that usually works without effort (e.g. to define a rational number whose denominator is non-zero). And therefore I'd also appreciate knowing more about what the technical issue is behind the original design (forgetting for a moment that it is unnecessarily complicated).
Any pointer would be appreciated!
Damiano Testa (Jan 05 2026 at 11:41):
I don't know how to impose such constraints. I am also not sure whether it is possible or not.
Eric Wieser (Jan 05 2026 at 11:54):
Here's one way to impose constraints:
inductive Tree : Bool → Type where
| nil : Tree true
| leaf
(string? : Option String)
{lisNil risNil}
(left : Tree lisNil)
(right : Tree risNil)
(check : string?.isSome → lisNil ∧ risNil) :
Tree false
Eric Wieser (Jan 05 2026 at 11:55):
I wouldn't recommend using that here, but it perhaps shows you another tool that is available
Sébastien Boisgérault (Jan 05 2026 at 12:14):
Eric Wieser said:
I wouldn't recommend using that here, but it perhaps shows you another tool that is available
Agreed. :praise: Thanks a lot for this method!
Last updated: Feb 28 2026 at 14:05 UTC