Zulip Chat Archive

Stream: lean4

Topic: Hypothesis in `match`


Horatiu Cheval (Dec 19 2021 at 08:29):

Consider the snippet below. I want to define the function foo through a dependent if-then-else, and to do pattern matching on one of the branches. But the hypothesis hgiven by if is in some patterns absurd, i.e. I am on the true branch but I know that the function is always false one some pattern, so foo is trivially defined through exfalso there. The problem is that the hypothesis from if remains stated in the local context in terms of the general variable t, instead of by replacing t with its form in the current pattern. Can this be done?

inductive Term
| var : Nat  Term
| app : Term  Term  Term

open Term

def bar : Term  Bool := sorry -- let's say this is some function which returns `false` on `var (i + 1)`

def foo (t : Term) : Term :=
  if h : bar t then match t with
    -- here `t` should be `i + 1`,but how do I get that `bar t = bar (i + 1)`?
    -- I know `h : bar t`, but `bar $ var (i + 1)` is false, si I want to apply False elimination
    | var (i + 1) => _
    /-
    context:
    t : Term
    h : bar t = true
    i : Nat
    ⊢ Term
    -/
    | _ => sorry
  else sorry

Alexander Bentkamp (Dec 19 2021 at 09:58):

You can also match on h:

def foo (t : Term) : Term :=
  if h : bar t then match t, h with
    | var (i + 1), h' => _
    /-
    t : Term
    h : bar t = true
    i : Nat
    h' : bar (var (i + 1)) = true
    -/
    | _, _ => sorry
  else sorry

Sebastian Ullrich (Dec 19 2021 at 10:05):

Or, equivalently, match (generalizing := true) t with

Sebastian Ullrich (Dec 19 2021 at 10:16):

Added to the match docstring.

Horatiu Cheval (Dec 19 2021 at 10:56):

Great, thank you both!

Andrés Goens (Feb 19 2023 at 13:00):

I have a similar issue to this where match (generalizing := true) doesn't seem to substitute the variables matched on. This is an #MWE:

import Std
abbrev State := Std.HashMap Nat Nat
inductive IsVal : State  Nat  Option Nat  Prop
  | mk : IsVal s n (s.find? n)

instance (s : State) (n : Nat) (n? : Option Nat) : Decidable (IsVal s n n?) :=
  let v := s.find? n
  match (generalizing := true) v, n? with
    | none, none => isTrue (by
    /- Information lost that v = none:
       Goals (1)
       s : State
       n : Nat
       n? : Option Nat
       v : Option Nat := Std.HashMap.find? s n
       ⊢ IsVal s n none
    -/

Is there any way to keep the information that s.find? n = none in that case?

Arthur Paulino (Feb 19 2023 at 13:04):

(deleted)

Arthur Paulino (Feb 19 2023 at 13:41):

As a workaround you can do two consecutive matches and deal with the inner cases separately

Kyle Miller (Feb 19 2023 at 14:00):

I think you're not really able to do generalization on let bindings. This works for the first case:

instance (s : State) (n : Nat) (n? : Option Nat) : Decidable (IsVal s n n?) :=
  match h : s.find? n, n? with
    | none, none => isTrue <| by
      rw [ h]
      constructor
    | _, _ => sorry

Kyle Miller (Feb 19 2023 at 14:04):

Here's probably an easier way to go about defining this instance though:

theorem IsVal_iff (s : State) (n : Nat) (n? : Option Nat) :
    IsVal s n n?  n? = s.find? n := by
  constructor
  · intro h
    cases h
    constructor
  · intro h
    subst_vars
    constructor

instance (s : State) (n : Nat) (n? : Option Nat) : Decidable (IsVal s n n?) :=
  if h : n? = s.find? n then
    isTrue <| by rwa [IsVal_iff]
  else
    isFalse <| by rwa [IsVal_iff]

Andrés Goens (Feb 19 2023 at 14:18):

oh that's interesting, I didn't know you could do match h : ... with like in an if, that's exactly what I was looking for. Thanks! (the example was a simpler version just to show the issue)


Last updated: Dec 20 2023 at 11:08 UTC