Zulip Chat Archive
Stream: lean4
Topic: Proving termination for Parsec
Yakov Pechersky (Oct 30 2022 at 16:56):
Consider:
import Lean.Data.Parsec
open Lean
def moveToEnd : Parsec Unit := do
let c ← Parsec.anyChar
dbg_trace c
moveToEnd <|> pure ()
#eval moveToEnd.run "ab"
What's the right approach to prove termination here? Use an explicit fun it
?
Yakov Pechersky (Oct 31 2022 at 04:23):
I seem to have made some progress with my moveToEnd
and moveToEnd'
below, but now I don't know why the moveToEnd'
has two independent String.Iterator
s. For the case of the more "manual" definition in moveToEnd
, how do I restrict the termination obligation to just a subset of cases where it.hasNext
? Since if that's not true, then one terminates right away.
import Lean.Data.Parsec
theorem Nat.lt_add_right_iff {m n : Nat} : m < m + n ↔ 0 < n := by sorry
theorem Nat.sub_lt_sub_left_of_le {a b c : Nat} (h : b ≤ a) (h' : c < b) :
a - b < a - c := by sorry
open Lean
theorem csize_pos (c : Char) : 0 < String.csize c := String.one_le_csize c
theorem pos_le_pos_iff {p q : String.Pos} : p ≤ q ↔ p.byteIdx ≤ q.byteIdx := Iff.rfl
theorem pos_lt_pos_iff {p q : String.Pos} : p < q ↔ p.byteIdx < q.byteIdx := Iff.rfl
@[simp] theorem byteIdx_pos_add_char (p : String.Pos) (c : Char) :
(p + c).byteIdx = p.byteIdx + String.csize c := rfl
theorem pos_lt_add_char_right (p : String.Pos) (c : Char) : p < p + c := by
simp [pos_lt_pos_iff, Nat.lt_add_right_iff, csize_pos]
@[simp] theorem String.Iterator.s_next (it : String.Iterator) : it.next.s = it.s := rfl
@[simp] theorem String.Iterator.pos_next (it : String.Iterator) : it.next.pos = it.s.next it.pos := rfl
def moveToEnd : Parsec Unit := fun it => Id.run <| do
let Parsec.ParseResult.success _ c ← Parsec.anyChar it | return Parsec.ParseResult.error it "end"
dbg_trace c
return moveToEnd it.next
termination_by moveToEnd it => it.s.length - it.pos.byteIdx
decreasing_by {
-- a✝: String.Iterator -- only one such String.Iterator
rename String.Iterator => it
simp_wf
simp
refine Nat.sub_lt_sub_left_of_le ?_ ?_
sorry
sorry
}
def moveToEnd' : Parsec Unit := fun it => ((do
let c ← Parsec.anyChar
dbg_trace c
moveToEnd') <|> pure () : Parsec Unit) it
termination_by moveToEnd' it => it.s.length - it.pos.byteIdx
decreasing_by {
-- a✝¹a✝: String.Iterator -- two such String.Iterators
rename String.Iterator => it -- (aside, how do I rename both)
simp_wf
sorry
}
#eval moveToEnd.run "ab"
#eval moveToEnd'.run "ab"
Last updated: Dec 20 2023 at 11:08 UTC