Zulip Chat Archive
Stream: maths
Topic: recursive definitions
Eric Rodriguez (Apr 14 2021 at 16:51):
Hey all, I'm just wondering what sort of ideas there are to help nudge the equation compiler realise that an induction is fair dos. I've read this and none of it was helpful -- apart from the last one, which may well be; I didn't get rel_tac
.
For reference, I'm trying to define the membership of an arrow in a path (on quivers); I attach the code below. The issue, I think, is that I need to take a couple generic type arguments before recursing on the path itself, which confuses the compiler and makes it think it needs to check the induction on the typeparams; the path is defined kind of like a list, and so the size is clearly strictly decreasing. There's even a definition path.length
, which makes me feel like if I could get that working with rel_tac
it would work fine.
Eric Rodriguez (Apr 14 2021 at 16:51):
import tactic
import combinatorics.quiver
universes v u
open quiver
inductive same_arrow {V} (q : quiver V) : ∀ {a b c d : V}, (q.arrow a b) → (q.arrow c d) → Prop
| refl {a b : V} (e : q.arrow a b) : same_arrow e e
def mem_path' {V : Type u} (q : quiver.{v} V) : ∀ {a b c d : V}, q.path c d → q.arrow a b → Prop
| _ _ _ _ (path.nil) := λ hom, false
| a b c d (path.cons h t) := λ hom, (same_arrow q hom t) ∨ (mem_path' h hom)
def mem_path {V : Type u} (q : quiver.{v} V) : ∀ {a b : V}, q.path a b → q.total → Prop
| _ _ (path.nil) := λ hom, false
| a b (@path.cons _ _ _ c _ h t) := λ hom, mem_path h hom ∨
(hom = { source := c,
target := b,
arrow := t })
Adam Topaz (Apr 14 2021 at 17:00):
I would immitate the definition of src#list.mem
Eric Rodriguez (Apr 14 2021 at 17:02):
it's pretty much equal, modulo some workarounds for types not being defeq
Adam Topaz (Apr 14 2021 at 17:06):
I'm confused as to why you need same_arrow
Eric Rodriguez (Apr 14 2021 at 17:08):
hom
is of type q.arrow a b
, but t : q.arrow ?m_1 d
; equality wouldn't typecheck
Adam Topaz (Apr 14 2021 at 17:11):
Ah ok
Adam Topaz (Apr 14 2021 at 17:22):
I think this works?
import tactic
import combinatorics.quiver
universes v u
open quiver
inductive foo {V : Type u} (Q : quiver.{v} V) : Π {a b c d : V}, Q.arrow a b → Q.path c d → Prop
| base {a b} (f : Q.arrow a b) : foo f (quiver.path.cons quiver.path.nil f)
| induct {a b c d x : V} {f : Q.arrow a b} {g : Q.arrow c d} {h : Q.path x c} :
foo f h → foo f (quiver.path.cons h g)
Adam Topaz (Apr 14 2021 at 17:27):
Obviously the names should be changed :wink:
Mario Carneiro (Apr 14 2021 at 17:49):
In both cases you can fix the errors by moving parameters that don't change left of the colon
def mem_path' {V : Type u} (q : quiver.{v} V) {a b} (hom : q.arrow a b) {c} :
∀ {d : V}, q.path c d → Prop
| _ path.nil := false
| _ (path.cons h t) := same_arrow q hom t ∨ mem_path' h
def mem_path {V : Type u} (q : quiver.{v} V) {a} (hom : q.total) : ∀ {b : V}, q.path a b → Prop
| _ path.nil := false
| _ (path.cons h t) := mem_path h ∨ hom = ⟨_, _, t⟩
Mario Carneiro (Apr 14 2021 at 17:50):
I also moved the hom
argument left of the colon, which reverses the arguments, but it works even with that one on the other side. The only parameter that really matters is {c}
in the first and {a}
in the second definition, that is, the first argument of q.path
, which is a parameter of the inductive
Eric Rodriguez (Apr 14 2021 at 18:02):
Thanks for that idea Adam, I ended up playing with it, and I think you need to make base
instead be:
| base {a b c : V} (f : a ⟶ b) : ∀ p : path c a, foo f (p.cons f)
but otherwise it seems to work!
(The defn you gave me ends up being essentially p.starts_with
, as far as I could tell)
Eric Rodriguez (Apr 14 2021 at 18:03):
And thanks too, Mario; I was worried that if I moved them left, I wouldn't be able to induct properly. I know there's a subtle difference between params left of and params right of the colon, but I'm not too sure what it is; do you know where I can read more about them?
Adam Topaz (Apr 14 2021 at 18:09):
Yes you're right @Eric Rodriguez ! My definition just says that the arrow is the first thing in the path, but with your change it should work :smile:
Mario Carneiro (Apr 14 2021 at 18:09):
the difference is that variables on the left are considered "parameters" and don't change during the recursion. For an inductive type, you generally want the "parameters" of the inductive on the left and the "indices" on the right
Mario Carneiro (Apr 14 2021 at 18:10):
this ensures that lean determines that it is recursive in the right way
Eric Rodriguez (Apr 14 2021 at 18:18):
thanks Mario, that makes sense!
Last updated: Dec 20 2023 at 11:08 UTC