Zulip Chat Archive
Stream: lean4
Topic: Don't pattern match on composed constructors?
Brandon Brown (Jun 07 2021 at 05:54):
I've written an integer type as a subtype of a "pre-integer" base type based on whether the base int is in an acceptable normal form.
Now I'm trying to prove things about my is_norm
function, e.g. that a base int of the form succ^n pred
is in normal form according to is_norm
. I've defined two versions of the is_norm
predicate, the first was what first came to mind, but it was seemingly impossible to prove that is_norm (succ^n pred) = true
whereas redefining the function using nested functions made it straightforward. Is the lesson here that I should always avoid defining functions that use pattern matching on composed constructors, e.g. succ (pred a)
because the resulting proofs are extremely difficult or is there an equally easy proof using my first is_norm
function that's just not obvious to me?
MWE:
inductive b_int : Type
| zero : b_int
| succ : b_int → b_int
| pred : b_int → b_int
open b_int
-- Initial version, very straightforward definition
def is_norm (a : b_int) : Bool :=
match a with
| zero => true
| succ (pred a) => false
| pred (succ a) => false
| succ a => is_norm a
| pred a => is_norm a
-- More elaborate, but ends up making proof way easier?
def is_norm'' (a : b_int) : Bool :=
match a with
| zero => true
| succ a => isSucc a
| pred a => isPred a
where
isSucc (b : b_int) : Bool :=
match b with
| pred b => false
| zero => true
| succ b => isSucc b
isPred (c : b_int) : Bool :=
match c with
| succ c => false
| zero => true
| pred c => isPred c
def int := {x : b_int // is_norm x}
-- This is to define a b_int that only uses either succ or pred repeatedly
def fun_pow {α : Type _} (f : α → α) (n : Nat) (a : α) : α :=
match n with
| 0 => a
| (n+1) => f (fun_pow f n a)
#reduce fun_pow b_int.succ 5 zero -- succ (succ (succ (succ (succ zero))))
example : is_norm (zero.pred.succ.succ) = false := by rfl
theorem fun_pow_succ_n {n : Nat} : fun_pow succ n.succ zero = succ (fun_pow succ n zero) := rfl
-- Fairly easy to prove with is_norm''
theorem succ_n_is_norm {n : Nat} : is_norm'' (fun_pow succ n zero) = true := by
induction n with
| zero => rfl
| succ n c =>
rw [fun_pow_succ_n]
have z₁ : is_norm'' (succ (fun_pow succ n zero)) = is_norm''.isSucc (fun_pow succ n zero) from rfl
rw [z₁]
induction n with
| zero => rfl
| succ l m =>
rw [fun_pow_succ_n]
have z₂ : is_norm''.isSucc (succ (fun_pow succ l zero)) = is_norm''.isSucc (fun_pow succ l zero) from rfl
rw [z₂];
assumption
-- I have no idea how to prove with the first is_norm:
theorem succ_n_is_norm2 {n : Nat} : is_norm (fun_pow succ n zero) = true := sorry
Sebastian Ullrich (Jun 07 2021 at 08:07):
You just have to do sufficient case splits until the is_norm
case is uniquely determined
theorem succ_n_is_norm2 {n : Nat} : is_norm (fun_pow succ n zero) = true := by
induction n with
| zero => rfl
| succ n ih =>
cases n with
| zero => rfl
| succ n => exact ih
Brandon Brown (Jun 07 2021 at 13:04):
Thank you!
Last updated: Dec 20 2023 at 11:08 UTC