Zulip Chat Archive
Stream: new members
Topic: Recursive RBSet in an inductive
Harry Goldstein (Jun 11 2024 at 03:45):
Hi all, I was here a few days ago asking about putting recursive lists in inductives, now I'm trying to put recursive RBSet
s in inductives. The problem is that I can't get the Ord instances to work out:
import Batteries.Data.RBMap.Basic
open Batteries (RBSet)
instance [Ord α] : Ord (List α) :=
let rec aux
| [], [] => Ordering.eq
| [], _ => Ordering.lt
| _, [] => Ordering.gt
| a::as, b::bs => match Ord.compare a b with
| Ordering.eq => aux as bs
| o => o
{ compare := λ x y => aux x y }
instance [Ord α] : Ord (RBSet α Ord.compare) := by
refine { compare := λ x y => Ord.compare x.toList y.toList }
inductive Value : Type :=
| unit
| map (m : RBSet Value Ord.compare)
deriving Ord
This should be valid in theory (the Ord instance is well-defined) but I can't tell if there's a way to convince Lean. Would love advice if you have any.
Bbbbbbbbba (Jun 11 2024 at 06:06):
I'm not sure the problem is in the Ord instance, because changing to | map (m : RBSet Value fun x y => Ordering.eq)
gives the same error message ((kernel) arg #1 of 'Value.map' contains a non valid occurrence of the datatypes being declared
).
Bbbbbbbbba (Jun 11 2024 at 07:50):
I wonder if it helps to first define
inductive Value : Type :=
| unit
| map (m : Batteries.RBNode Value)
and define the well-formedness of a Value
instance later.
Henrik Böving (Jun 11 2024 at 07:56):
Yes the RBNode
approach is the way to go here.
Notification Bot (Jun 11 2024 at 20:49):
Harry Goldstein has marked this topic as resolved.
Harry Goldstein (Jun 11 2024 at 20:49):
Got it, thanks!
Notification Bot (Jun 11 2024 at 20:52):
Harry Goldstein has marked this topic as unresolved.
Harry Goldstein (Jun 11 2024 at 21:03):
Hmm, I think there may still be an issue. If I define my well-formedness condition as a separate inductive, the proof that recursively contained values are actually well-formed can't be used for computation:
inductive Value.WF : Value → Prop
| wf_unit : WF Value.unit
| wf_map :
(∀ x ∈ m, WF x) →
m.WF Ord.compare →
WF (Value.map m)
def recursive : {v : Value // v.WF} → {v : Value // v.WF}
| ⟨Value.unit, h⟩ => ⟨Value.unit, h⟩
| ⟨Value.map m, h⟩ => by
refine ⟨Value.map (RBNode.map (λ v => recursive v) m), ?_⟩
In that last line, I can't prove that v
is a {v : Value // v.WF}
because in order to do that I'd need to pattern match on h
(which doesn't seem to be allowed).
Bbbbbbbbba (Jun 12 2024 at 02:15):
But one problem is that in refine ⟨Value.map f m), ?_⟩
, f
must take any v : Value
as its argument, without the hypothesis v ∈ m
so we cannot assert that the output of f
is well-formed. Maybe there is an alternate version (or a better use pattern) of map
that solves this problem.
Harry Goldstein (Jun 12 2024 at 03:14):
Even if we could show that v ∈ m
, I'm not sure we could actually get to the proof that it is a valid Value
, but yes, that's an issue too.
Bbbbbbbbba (Jun 12 2024 at 04:06):
This is where I got to
def recursive : {v : Value // v.WF} → {v : Value // v.WF}
| ⟨Value.unit, h⟩ => ⟨Value.unit, h⟩
| ⟨Value.map m, h⟩ => by
have f := λ v => recursive ⟨v, by
cases h with
| wf_map h0 h1 =>
have hv : v ∈ m := sorry
exact h0 v hv
⟩
let f0 := λ v => (f v).val
refine ⟨Value.map (RBNode.map f0 m), ?_⟩
constructor
. intro x hx
have hmap: ∃v ∈ m, x = f0 v := sorry
match hmap with
| ⟨v, ⟨hv0, hv1⟩⟩ =>
rw [hv1]
exact (f v).property
. show RBNode.WF compare (RBNode.map f0 m)
sorry
decreasing_by sorry
Mario Carneiro (Jun 13 2024 at 21:53):
To do this you probably need something like docs#List.attach for RBNode, which can then be composed with RBNode.map
so that you have a condition to make the descent well founded. Ping @Joachim Breitner : this is another instance of the general problem where proving theorems about nested inductives requires some user-extensible mechanism for doing the equivalent of the ite
-> dite
replacement trick to get more assumptions in the context when doing a recursive call via map
Last updated: May 02 2025 at 03:31 UTC