open nat
notation `⟦`:max a `⟧`:0 := cast (by simp) a

inductive vector (α : Type) : nat → Type
| nil {} : vector 0
| cons   : Π {n}, α → vector n → vector (succ n)

namespace vector
local attribute [simp] add_succ succ_add add_comm

variable {α : Type}

def app : Π {n m : nat}, vector α n → vector α m → vector α (n + m)
| 0        m nil        w := ⟦ w ⟧
| (succ n) m (cons a v) w := ⟦ cons a (app v w) ⟧

lemma app_nil_right {n : nat} (v : vector α n) : app v nil == v :=
begin induction v, reflexivity, {[smt] ematch_using [app, add_comm, zero_add, add_zero] }, end

def smt_cfg : smt_config :=
{ cc_cfg := {ac := ff}}

lemma app_assoc {n₁ n₂ n₃ : nat} (v₁ : vector α n₁) (v₂ : vector α n₂) (v₃ : vector α n₃) :
                     app v₁ (app v₂ v₃) == app (app v₁ v₂) v₃ :=
begin
  intros,
  induction v₁,
  {[smt] ematch_using [app, zero_add] },
  {[smt] with smt_cfg, repeat { ematch_using [app, add_succ, succ_add, add_comm, add_assoc] }}
end

def rev : Π {n : nat}, vector α n → vector α n
| 0     nil         := nil
| (n+1) (cons x xs) := app (rev xs) (cons x nil)

lemma rev_app : ∀ {n₁ n₂ : nat} (v₁ : vector α n₁) (v₂ : vector α n₂),
  rev (app v₁ v₂) == app (rev v₂) (rev v₁) :=
begin
  intros,
  induction v₁,
  {[smt] repeat {ematch_using [app, rev, zero_add, add_zero, add_comm, app_nil_right]}},
  {[smt] repeat {ematch_using [app, rev, zero_add, add_zero, add_comm, app_assoc, add_one_eq_succ]} }
end

end vector
