open tactic

set_option pp.all true

def g : nat → nat := λ x, x + 5

example (a b : nat) (p : nat → Prop) (h : p (g (nat.succ (nat.succ a)))) : p (g (a + 2)) :=
by do
  t ← target,
  new_t ← dsimplify (λ e, failed)
     (λ e,
        do { new_e ← unfold_projection e, return (new_e, tt) }
        <|>
        do {
         guard ([`add, `nat.add, `one, `zero]^.any e^.is_app_of),
         /- We are using transparency.none, so

            nat.add a (bit0 (nat.succ nat.zero))

            cannot be matched with

            nat.add ?a (nat.succ ?b)
         -/
         new_e ← dunfold_expr_core transparency.none e, trace e,
         trace "===>", trace new_e, trace "-------",
         return (new_e, tt) })
     t,
  trace new_t,
  expected ← to_expr `(p (g (nat.add a (bit0 (nat.succ nat.zero))))),
  guard (new_t = expected),
  trace new_t,
  assumption


example (a b : nat) (p : nat → Prop) (h : p (g (nat.succ (nat.succ a)))) : p (g (a + nat.succ (nat.succ 0))) :=
by do
  t ← target,
  new_t ← dsimplify (λ e, failed)
     (λ e,
        do { new_e ← unfold_projection e, return (new_e, tt) }
        <|>
        do {
         guard ([`add, `nat.add, `one, `zero]^.any e^.is_app_of),
         new_e ← dunfold_expr_core transparency.none e, trace e,
         trace "===>", trace new_e, trace "-------",
         return (new_e, tt) })
     t,
  trace new_t,
  expected ← to_expr `(p (g (nat.succ (nat.succ a)))),
  guard (new_t = expected),
  trace new_t,
  assumption
