Zulip Chat Archive

Stream: Is there code for X?

Topic: Proving List.reverseRecOn is correct


Eric Wieser (Mar 09 2024 at 02:28):

Is this statement provable? It feels like it needs some clever generalization trick that I'm out of practice with:

import Mathlib.Data.List.Basic

namespace List

-- the easy one
@[simp]
theorem reverseRecOn_nil {motive : List α  Sort*} (nil : motive [])
    (append_singleton :  (l : List α) (a : α), motive l  motive (l ++ [a])) :
    reverseRecOn [] nil append_singleton = nil :=
  rfl

-- I can't make any progress here
@[simp]
theorem reverseRecOn_concat {motive : List α  Sort*} (x : α) (xs : List α) (nil : motive [])
    (append_singleton :  (l : List α) (a : α), motive l  motive (l ++ [a])) :
    reverseRecOn (C := motive) (xs ++ [x]) nil append_singleton =
      append_singleton _ _ (reverseRecOn (C := motive) xs nil append_singleton) := by
  sorry

Eric Wieser (Mar 09 2024 at 02:28):

(docs#List.reverseRecOn)

Eric Wieser (Mar 09 2024 at 02:29):

I tried changing the definition to

def reverseRecOn {motive : List α  Sort*} (l : List α) (nil : motive [])
    (append_singleton :  (l : List α) (a : α), motive l  motive (l ++ [a])) : motive l :=
  match h : reverse l with
  | [] => cast (congr_arg motive <| pf1 h) nil
  | head :: tail =>
    cast (congr_arg motive <| pf2 h) <|
      append_singleton _ head <| reverseRecOn (reverse tail) nil append_singleton
termination_by l.length
decreasing_by
  have : tail.length < l.length := by
    rw [ length_reverse l, h, length_cons]
    simp [Nat.lt_succ]
  simpa only [InvImage, length_reverse]
where
  pf1 (h : reverse l = []) : [] = l := by simpa using congr(reverse $h.symm)
  pf2 {head tail} (h : reverse l = head :: tail) : reverse tail ++ [head] = l := by
    simpa using congr(reverse $h.symm)

but it didn't seem to help; the match h : _ is super hard to do anything with

Eric Wieser (Mar 09 2024 at 03:02):

Ah, got it: #11257

Eric Wieser (Mar 09 2024 at 11:47):

A follow-up puzzle:

@[simp]
theorem bidirectionalRec_cons_append {motive : List α  Sort*}
    (nil : motive []) (singleton :  a : α, motive [a])
    (cons_append :  (a : α) (l : List α) (b : α), motive l  motive (a :: (l ++ [b])))
    (a : α) (l : List α) (b : α) :
    bidirectionalRec nil singleton cons_append (a :: (l ++ [b])) =
      cons_append a l b (bidirectionalRec nil singleton cons_append l) := by
  cases l
  · simp [bidirectionalRec]
  · simp_rw [List.cons_append, bidirectionalRec, List.cons_append]
    sorry

Wrenna Robson (Jun 07 2024 at 16:12):

Is there a reason we don't have List.reverseRec?

Yaël Dillies (Jun 07 2024 at 16:13):

Looks like an oversight

Eric Wieser (Jun 07 2024 at 16:34):

Arguably having On variants of recursion functions is a waste of time

Floris van Doorn (Jun 07 2024 at 17:04):

I agree, especially since nowadays we can choose the order of arguments ourselves using named arguments.


Last updated: May 02 2025 at 03:31 UTC