Zulip Chat Archive

Stream: new members

Topic: Possible to eliminate impossible cases? without proofs?


aron (Apr 16 2025 at 19:26):

I have defined an inductive type BoundedList t (min : Nat) (max : Nat) whose constructors should make it impossible for min to ever be larger than max.

When I match on a BoundedList t 0 2 Lean can indeed eliminate a lot of patterns as impossible, where the matched pattern would result in a straightforward type contradiction. But it can't seem to figure out a slightly subtler invariant of my type: that there would be no way to construct a value in whose type min > max.

Is there any way to tell Lean that those patterns are impossible? Ideally without having to construct a proof for it?

(the commented out patterns are where Lean has correctly eliminated those patterns as impossible)

set_option linter.unusedVariables false

inductive BoundedList (t : Type u) : (min : Nat)  (max : Nat)  Type u where
  | nil : BoundedList t 0 0
  | cons {min max : Nat} : (item : t)  BoundedList t min max  BoundedList t (.succ min) (.succ max)
  /-- Raises the upper bound by one. --/
  | raise {min max : Nat} : BoundedList t min max  BoundedList t min (.succ max)
  /-- Lowers the lower bound by one. --/
  | lower {min max : Nat} : BoundedList t (.succ min) (.succ max)  BoundedList t min (.succ max)


example : BoundedList t 0 2  Unit
  -- | .nil => ()
  -- | .cons _ _ => ()
  | .raise l =>
    match h : l with
    -- | .nil => ()
    -- | .cons _ _ => ()
    | .raise .nil => ()
    | .lower l' =>
      match h' : l' with
      -- | .nil => ()
      | .cons _ .nil => ()
      | .raise l'' => () -- this should be impossible – there's no way to make a BL with a min bound that's higher than its max bound
      | .lower l'' => () -- this should be impossible

  | .lower l =>
    match h : l with
    -- | .nil => ()
    | .cons _ l' =>
      match h' : l' with
      -- | .nil => ()
      -- | .cons _ _ => ()
      | .raise .nil => ()
      | .lower l'' =>
        match h'' : l'' with
        -- | .nil => ()
        | .cons _ .nil => ()
        | .raise l''' => () -- this should be impossible
        | .lower l''' => () -- this should be impossible

    | .raise l' =>
      match h' : l' with
      -- | .nil => ()
      | .cons _ .nil => ()
      | .raise l'' => () -- this should be impossible
      | .lower l'' => () -- this should be impossible

    | .lower l' =>
      match h' : l' with
      -- | .nil => ()
      | .cons _ l'' =>
        match h'' : l'' with
        -- | .nil => ()
        | .cons _ .nil => ()
        | .raise l''' => () -- this should be impossible
        | .lower l''' => () -- this should be impossible

      | .raise l'' => () -- this should be impossible
      | .lower l'' => () -- this should be impossible

Robin Arnez (Apr 17 2025 at 21:30):

I have been able to do this:

theorem BoundedList.le {t : Type u} {min max : Nat} (x : BoundedList t min max) : min  max := by
  induction x with
  | nil => exact Nat.le_refl _
  | cons _ l ih => exact Nat.succ_le_succ ih
  | raise _ ih => exact Nat.le_succ_of_le ih
  | lower _ ih => exact Nat.le_of_succ_le ih

example (x : BoundedList t 0 2) : Unit :=
  have : BoundedList t 2 1  False := (by decide)  BoundedList.le
  have this' : BoundedList t 3 2  False := (by decide)  BoundedList.le
  match x with
  | .raise l =>
    match l with
    | .raise .nil => ()
    | .lower l' =>
      match l', this with
      | .cons _ .nil, _ => ()
  | .lower l =>
    match l with
    | .cons _ l' =>
      match l' with
      | .raise .nil => ()
      | .lower l'' =>
        match l'', this with
        | .cons _ .nil, _ => ()
    | .raise l' =>
      match l', this with
      | .cons _ .nil, _ => ()
    | .lower l' =>
      match l', this, this' with
      | .cons _ l'', _, _ =>
        match l'', this with
        | .cons _ .nil, _ => ()

The trick is to give match more helpers to work with.


Last updated: May 02 2025 at 03:31 UTC