-- Frap/Sort.lean

inductive Permutation {α : Type} : List α → List α → Prop :=
  | perm_nil : Permutation [] []
  | perm_skip x l l'
      : Permutation l l' → Permutation (x::l) (x::l')
  | perm_swap x y l : Permutation (y::x::l) (x::y::l)
  | perm_trans l l' l''
      : Permutation l l' → Permutation l' l''
        → Permutation l l''

open Permutation

-- Repository definitions used:
content: ...

-- Repository lemmas used:
content: theorem append_assoc (as bs cs : List α)
        : (as ++ bs) ++ cs = as ++ (bs ++ cs)

-- Local definitions used:
content: inductive Permutation {α : Type} : List α → List α → Prop :=
  | perm_nil : Permutation [] []
  | perm_skip x l l'
      : Permutation l l' → Permutation (x::l) (x::l')
  | perm_swap x y l : Permutation (y::x::l) (x::y::l)
  | perm_trans l l' l''
      : Permutation l l' → Permutation l' l''
        → Permutation l l''

-- Local lemmas used:
content: theorem permutation_refl (l : List α) : Permutation l l

content: theorem permutation_symm (l l' : List α)
    : Permutation l l' → Permutation l' l

content: theorem permutation_app_tail (l l' tl : List α)
    : Permutation l l' → Permutation (l++tl) (l'++tl)

content: theorem permutation_app_head (l tl tl' : List α)
    : Permutation tl tl' → Permutation (l++tl) (l++tl')

content: theorem permutation_cons_append (l : List α) x
    : Permutation (x :: l) (l ++ [x])

-- Target theorem and proof:
theorem permutation_app_comm (l l' : List α)
    : Permutation (l ++ l') (l' ++ l)
:= by
  induction l with simp
  | nil => apply permutation_refl
  | cons a al ih =>
    -- a :: (al ++ l')
    -- al ++ l' ++ [a]
    -- l' ++ al ++ [a]
    -- l' ++ (al ++ [a])
    -- l' ++ a :: al
    apply perm_trans
    . apply permutation_cons_append
    . apply perm_trans
      . apply permutation_app_tail; exact ih
      . rw [List.append_assoc]
        apply permutation_app_head
        apply permutation_symm
        apply permutation_cons_append