Zulip Chat Archive

Stream: new members

Topic: non-empty lists, again


Vincent Beffara (Oct 25 2019 at 22:04):

Hi again,
Still playing around with various ways to define non-empty lists, this time following advice and using V \times list V to be able to use library functions. I still would like to make inductive definitions using pattern matching (if only for practice), but I am getting complaints about well-founded relations,

def llist (V : Type) : Type := V × list V

def simple {V : Type} : llist V -> Prop
    | v,[]   := true
    | v,w::l := ¬ v  w::l  simple w,l

What would be the proper way to do what I want? It would be very nice to avoid auxiliary functions and piling to_list and from_list, because that would push me towards defining an inductive type and having to reinvent the wheel...

Bryan Gin-ge Chen (Oct 25 2019 at 22:42):

Unfortunately I haven't been able to solve your issue but this is the doc page that's usually suggested when Lean has trouble proving something well-founded. Apologies if you've already seen it.

Bryan Gin-ge Chen (Oct 26 2019 at 07:17):

This works:

def llist (V : Type) : Type := V × list V

def simple {V : Type} : llist V  Prop
    | (v,[])   := true
    | (v,w::l) := ¬ v  w::l  simple (w,l)
    using_well_founded {rel_tac := λ _ _, `[exact ⟨_, measure_wf (list.length  prod.snd)]}

Vincent Beffara (Oct 26 2019 at 20:06):

Thanks for the working version! Still the version with an auxiliary function,

def simple_l {V : Type} : list V -> Prop | [] := true | (x::xs) := ¬ x  xs  simple_l xs

def simple {V : Type} : V × list V -> Prop | (x,xs) := simple_l (x::xs)

feels much simpler. I'm ok with incantations about measure_wf that I don't understand (yet?) but I really would prefer not having to put them near the definition of simple because there are a lot of other things that I am defining in a similar way.

Vincent Beffara (Oct 26 2019 at 20:29):

Ah, in fact I still get an error with your version:

error: failed to prove recursive application is decreasing, well founded relation
  @has_well_founded.r (llist V)
    (@has_well_founded.mk (llist V) (@measure (llist V) (λ (l : llist V), @length V (@prod.snd V (list V) l))) _)
The nested exception contains the failure state for the decreasing tactic.
nested exception message:
tactic failed, there are no goals to be solved

Vincent Beffara (Oct 26 2019 at 20:31):

But this does:

def simple {V : Type} : llist V  Prop
    | (v,[])   := true
    | (v,w::l) := have length l < length (w::l), by { simp }, ¬ v  w::l  simple (w,l)
    using_well_founded wf_tacs

Kevin Buzzard (Oct 26 2019 at 20:32):

Bryan's version works for me. Which version of Lean are you using?

Bryan Gin-ge Chen (Oct 26 2019 at 20:33):

Ah, my version fails if I add import data.list.basic...

Kevin Buzzard (Oct 26 2019 at 20:33):

because simp gets too good.

Vincent Beffara (Oct 26 2019 at 20:34):

All right, explanation is in mathlib/src/tactic/well_founded_tactics.lean

Bryan Gin-ge Chen (Oct 26 2019 at 20:34):

Yep, you need to add a dec_tac line from that file:

import tactic.well_founded_tactics
import data.list.basic

def llist (V : Type) : Type := V × list V

def simple {V : Type} : llist V  Prop
    | (v,[])   := true
    | (v,w::l) := ¬ v  w::l  simple (w,l)
    using_well_founded {rel_tac := λ _ _, `[exact ⟨_, measure_wf (list.length  prod.snd)],
    dec_tac := well_founded_tactics.default_dec_tac'}

Bryan Gin-ge Chen (Oct 26 2019 at 20:44):

I wonder if this issue with default_dec_tac described in tactic/well_founded_tactics.lean is something which ought to be addressed in 3.5? @Simon Hudon

Vincent Beffara (Oct 26 2019 at 20:48):

In the meantime, is there any way to attach the information to use wf_tacs to the type llist V rather than having to mention it with every inductive definition?

Vincent Beffara (Oct 26 2019 at 20:49):

Or to cheat by using a slightly more complicated measure instead of list.length so that the default tactic works again, but that would feel a little dirty ...

Bryan Gin-ge Chen (Oct 26 2019 at 20:50):

I would be curious to know the answers to those questions too.

Vincent Beffara (Oct 26 2019 at 20:51):

Like so:

def llist (V : Type) : Type := V × list V
instance llist_wf {V : Type} : has_well_founded (llist V) := ⟨_, measure_wf ((λ n, n+n)  list.length  prod.snd)

def simple {V : Type} : llist V  Prop
    | (v,[])   := true
    | (v,w::l) := ¬ v  w::l  simple (w,l)

Bryan Gin-ge Chen (Oct 26 2019 at 20:53):

What's the reason for (λ n, n+n) ? I removed it and it still works for me.

Vincent Beffara (Oct 26 2019 at 20:54):

Ah, that's the dirty trick to answer my second question, if I leave it out then it fails again with the "no goals to be solved" error

Bryan Gin-ge Chen (Oct 26 2019 at 20:55):

Yes, you're right. I had some interfering definitions that confused me.

Vincent Beffara (Oct 26 2019 at 20:56):

(\lambda n, 2*n) apparently is too transparent though

Mario Carneiro (Oct 26 2019 at 21:23):

I think simple_l is list.nodup

Vincent Beffara (Oct 26 2019 at 21:51):

Yes it is! Hadn't grepped for that ...


Last updated: Dec 20 2023 at 11:08 UTC