Zulip Chat Archive

Stream: Is there code for X?

Topic: Termination proof


Ka Wing Li (Dec 21 2025 at 08:00):

I am trying to get the following done. But it seems lean losses dependent information when proving termination through pattern matching

def n_leading_spaces (s : String) : Nat :=
  match s.toList with
  | [] => 0
  | ' ' :: t => 1 + n_leading_spaces (String.ofList t)
  | _ => 0
  termination_by s.length
  decreasing_by
    all_goals simp_wf
    sorry

Or is there a nice way to pattern match on string?

Kim Morrison (Dec 21 2025 at 09:34):

I would use something like s.chars.takeWhile (· == ' ') |>.size. (Not sure if those function names are right: but use the iterators.)

Jakub Nowak (Dec 21 2025 at 10:11):

Yes, if you match on property or output of function then termination checker won't work.

Jakub Nowak (Dec 21 2025 at 10:12):

You can do this:

def n_leading_spaces (s : String) : Nat := go s.toList
  where
  go (s : List Char) : Nat :=
    match s with
    | [] => 0
    | ' ' :: t => 1 + go t
    | _ => 0

But using API as Kim hinted should also work, and it might be less hassle.

Ka Wing Li (Dec 21 2025 at 15:21):

Thanks! I am wondering why hypotheses are not generated from pattern matching.

Aaron Liu (Dec 21 2025 at 15:22):

I think it's because it would clutter the infoview with matching hypotheses you usually don't need

Jakub Nowak (Dec 21 2025 at 15:34):

You can instruct match to generate hypothesis by modifying the match in the body of the function. Though, it's a bit weird that you have you modify the body of the function for the termination proof. I agree with you that termination checker should introduce match hypotheses by default. Just like e.g. split tactic does.

def n_leading_spaces (s : String) : Nat :=
  match h : s.toList with
  | [] => 0
  | ' ' :: t => 1 + n_leading_spaces (String.ofList t)
  | _ => 0
  termination_by s.length
  decreasing_by
    all_goals simp_wf
    guard_hyp h : s.toList = ' ' :: t

Last updated: Feb 28 2026 at 14:05 UTC