Zulip Chat Archive

Stream: lean4

Topic: Dependent `And`


Mac Malone (Nov 10 2023 at 20:23):

How does one write a dependent And in Lean 4? PSigma is not in Prop and Exists does not permit destructing into non-Prop.

-- tactic 'induction' failed, recursor 'Exists.casesOn' can only eliminate into Prop
example (i : Nat) (a : Array Nat) (law :  h : i < a.size, a.get i, h = 0) : Nat :=
  have lt_size, z_eq := law
  i

-- has type `Type`, but is expected to have type `Prop`
def law (i : Nat) (a : Array Nat) : Prop := Σ' h : i < a.size, a.get i, h = 0

Arthur Adjedj (Nov 10 2023 at 20:27):

Writing your own PropSigma also gives out a code generation error which, to me, looks like a bug:

inductive PropSigma {P : Prop} (Q : P  Prop) : Prop :=
  | intro : (p : P)  Q p  PropSigma Q

--unsupported `PropSigma.casesOn` application during code generation
example (i : Nat) (a : Array Nat) (law : PropSigma (λ h : i < a.size => a.get i, h = 0)) : Nat :=
  have lt_size, z_eq := law
  i

edit : nevermind, this behaviour is already documented in the relevant code.

Junyan Xu (Nov 10 2023 at 20:30):

(deleted)

Junyan Xu (Nov 10 2023 at 20:35):

With exists you can use

Classical.choose {α : Sort u} {p : α  Prop} (h :  x, p x) : α

and docs#Classical.choose_spec, but I agree when u = 0 (i.e. α : Prop) we should have a version not relying on the axiom of choice.

Mac Malone (Nov 10 2023 at 20:37):

Another hacky solution is:

inductive PropSigma {P : Prop} (Q : P  Prop) : Prop :=
| intro : (p : P)  ((p : P)  Q p)  PropSigma Q

abbrev PropSigma.fst {Q : P  Prop} : PropSigma Q  P | .intro h _ => h
abbrev PropSigma.snd {Q : P  Prop} : (s : PropSigma Q)  Q s.fst | .intro h f => f h

example (i : Nat) (a : Array Nat) (law : PropSigma (λ h : i < a.size => a.get i, h = 0)) : Nat :=
  have lt_size := law.fst
  have z_eq := law.snd
  i

But this removes the ability to use pattern matching syntax for proper destructing.

Junyan Xu (Nov 10 2023 at 20:40):

Hmm, docs#Exists.fst and docs#Exists.snd are already there! You can even write law.1 law.2.

Mac Malone (Nov 10 2023 at 20:44):

@Junyan Xu Interesting, so it is just the casesOn eliminator that is broken for this special case.

Junyan Xu (Nov 10 2023 at 20:47):

I think it's behaving as expected as your goal is Nat : Type not _ : Prop.

Junyan Xu (Nov 10 2023 at 20:50):

For example these work:

lemma Exists.fst' {b : Prop} {p : b  Prop} (h :  a, p a) : b := have a, _ := h; a
lemma Exists.snd' {b : Prop} {p : b  Prop} (h :  a, p a) : p h.fst' := have _, ha := h; ha

Mac Malone (Nov 10 2023 at 20:51):

@Junyan Xu Yes, but the problem is there is overlooked case of a dependent and which does need some type (possibly Exists) that properly destructors for it.

Mac Malone (Nov 10 2023 at 20:53):

However, given that .1 and .2 work for exists, there is the following less hacky solution to the problem:

abbrev Exists.toAnd {b : Prop} {p : b  Prop} (x : Exists p) : And b (p x.1) :=
  x.1, x.2

-- tactic 'induction' failed, recursor 'Exists.casesOn' can only eliminate into Prop
example (i : Nat) (a : Array Nat) (law :  h : i < a.size, a.get i, h = 0) : Nat :=
  have lt_size, z_eq := law.toAnd
  i

Junyan Xu (Nov 10 2023 at 20:55):

I see, apparently casesOn is designed to support more, as this works:

lemma And.fst {a b : Prop} (h : a  b) :  := have _, _ := h; 0

Junyan Xu (Nov 10 2023 at 20:55):

I suppose you could also do

have lt_size := law.1; have z_eq := law.2

In Lean 3 it used to be possible to do

obtain lt_size, z_eq := law.1, law.2

in tactic mode.

Eric Wieser (Nov 11 2023 at 00:12):

Junyan Xu said:

You can even write law.1 law.2.

How does this work?

Junyan Xu (Nov 11 2023 at 01:50):

I don't know! I think it's Lean 4's new feature and I don't think it work in Lean 3.
Probably related to https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/invalid.20kernel.20projection.20error.20error

Mac Malone (Nov 11 2023 at 01:54):

Eric Wieser said:

Junyan Xu said:

You can even write law.1 law.2.

How does this work?

I believe it is because the projection is treated as a separate function of type law.1 : Exists p -> Prop and thus eliminator with that function is eliminating into Prop which works whereas in the destructing case it is eliminating into the arbitrary return type.

Mario Carneiro (Nov 12 2023 at 06:54):

Projections are typechecked such that x.1 is valid iff x.casesOn fun a _ => a would be type correct


Last updated: Dec 20 2023 at 11:08 UTC