Zulip Chat Archive
Stream: new members
Topic: Type-valued induction on Finset?
aron (Dec 18 2025 at 10:52):
I can see there are multiple induction principles for Finsets, like cons_induction, induction, induction_on, etc. But the motive returns Prop for all of them. Is there no induction for it that can be used to return a Type?
I wouldn't mind using a match in a recursive function but because it's a complex type I don't think it's possible to match on it in the way that I'd like to, like Finset.induction does: matching on the empty set in one case and on an existing set with a new item inserted in the other.
Similarly, Finset.rec or Finset.recOn also expose the internals of the type, which I don't want to deal with. How can I do this?
aron (Dec 18 2025 at 11:06):
Or is this not possible because extracting one item from the set at a time would require the axiom of choice? but why? it's a finite set, and besides Finset is a Type, not a Prop
Aaron Liu (Dec 18 2025 at 11:11):
The elements of the finset are unordered, but all the induction principles have to build up in some order
Robin Arnez (Dec 18 2025 at 20:57):
Yeah it's the same reason you can't write a fully generic safe, computable fold over a Finset (if you think about it, recursors behave similarly to folds). Except you can write a recursor if you add a requirement that the order doesn't matter. Multiset already has this with docs#Multiset.rec so you can straightforwardly extend it to Finset:
import Mathlib
@[elab_as_elim]
def Finset.consRec {α : Type u} {motive : Finset α → Sort v} (empty : motive ∅)
(cons : ∀ (a : α) (s : Finset α) (h : a ∉ s), motive s → motive (.cons a s h))
(cons_cons : ∀ (a b : α) (s : Finset α) (ha : a ∉ s) (hb : b ∉ s) (hab : a ≠ b) (ih : motive s),
cons a _ (by simp [hab, ha]) (cons b s hb ih) ≍ cons b _ (by simp [hab.symm, hb]) (cons a s ha ih))
(s : Finset α) : motive s :=
Finset.casesOn s (Multiset.rec
(fun _ => empty)
(fun a s ih nd => cons a ⟨s, nd.of_cons⟩ (Multiset.nodup_cons.mp nd).1 (ih nd.of_cons))
(fun a b s ih => Function.hfunext (by rw [Multiset.cons_swap])
fun nd1 nd2 _ => cons_cons _ _ ⟨s, nd1.of_cons.of_cons⟩ _ _
(by simp only [Multiset.nodup_cons, Multiset.mem_cons, not_or] at nd1; simp [nd1]) _))
Last updated: Dec 20 2025 at 21:32 UTC