l3lab/ntp-mathlib huggingface dataset:
theorem foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) :
    foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
      (L.bind fun y => (permutationsAux2 t ts [] y id).2) ++ r := by
  

Proof state:
α : Type u_1
β : Type u_2
t : α
ts : List α
r L : List (List α)
⊢ foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
    (List.bind L fun y => (permutationsAux2 t ts [] y id).2) ++ r

Next tactic:
induction' L with l L ih
theorem foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) :
    foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
      (L.bind fun y => (permutationsAux2 t ts [] y id).2) ++ r := by
  induction' L with l L ih
  · 

Proof state:
case nil
α : Type u_1
β : Type u_2
t : α
ts : List α
r : List (List α)
⊢ foldr (fun y r => (permutationsAux2 t ts r y id).2) r [] =
    (List.bind [] fun y => (permutationsAux2 t ts [] y id).2) ++ r

Next tactic:
rfl
theorem foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) :
    foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
      (L.bind fun y => (permutationsAux2 t ts [] y id).2) ++ r := by
  induction' L with l L ih
  · rfl
  · 

Proof state:
case cons
α : Type u_1
β : Type u_2
t : α
ts : List α
r : List (List α)
l : List α
L : List (List α)
ih :
  foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
    (List.bind L fun y => (permutationsAux2 t ts [] y id).2) ++ r
⊢ foldr (fun y r => (permutationsAux2 t ts r y id).2) r (l :: L) =
    (List.bind (l :: L) fun y => (permutationsAux2 t ts [] y id).2) ++ r

Next tactic:
simp [ih]
theorem foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) :
    foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
      (L.bind fun y => (permutationsAux2 t ts [] y id).2) ++ r := by
  induction' L with l L ih
  · rfl
  · simp [ih]
    

Proof state:
case cons
α : Type u_1
β : Type u_2
t : α
ts : List α
r : List (List α)
l : List α
L : List (List α)
ih :
  foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
    (List.bind L fun y => (permutationsAux2 t ts [] y id).2) ++ r
⊢ (permutationsAux2 t ts ((List.bind L fun y => (permutationsAux2 t ts [] y id).2) ++ r) l id).2 =
    (permutationsAux2 t ts [] l id).2 ++ ((List.bind L fun y => (permutationsAux2 t ts [] y id).2) ++ r)

Next tactic:
rw [← permutationsAux2_append]
theorem mem_foldr_permutationsAux2 {t : α} {ts : List α} {r L : List (List α)} {l' : List α} :
    l' ∈ foldr (fun y r => (permutationsAux2 t ts r y id).2) r L ↔
      l' ∈ r ∨ ∃ l₁ l₂, l₁ ++ l₂ ∈ L ∧ l₂ ≠ [] ∧ l' = l₁ ++ t :: l₂ ++ ts := by
  

Proof state:
α : Type u_1
β : Type u_2
t : α
ts : List α
r L : List (List α)
l' : List α
⊢ l' ∈ foldr (fun y r => (permutationsAux2 t ts r y id).2) r L ↔
    l' ∈ r ∨ ∃ l₁ l₂, l₁ ++ l₂ ∈ L ∧ l₂ ≠ [] ∧ l' = l₁ ++ t :: l₂ ++ ts

Next tactic:
have :
    (∃ a : List α,
        a ∈ L ∧ ∃ l₁ l₂ : List α, ¬l₂ = nil ∧ a = l₁ ++ l₂ ∧ l' = l₁ ++ t :: (l₂ ++ ts)) ↔
      ∃ l₁ l₂ : List α, ¬l₂ = nil ∧ l₁ ++ l₂ ∈ L ∧ l' = l₁ ++ t :: (l₂ ++ ts) :=
    ⟨fun ⟨_, aL, l₁, l₂, l0, e, h⟩ => ⟨l₁, l₂, l0, e ▸ aL, h⟩, fun ⟨l₁, l₂, l0, aL, h⟩ =>
      ⟨_, aL, l₁, l₂, l0, rfl, h⟩⟩
theorem mem_foldr_permutationsAux2 {t : α} {ts : List α} {r L : List (List α)} {l' : List α} :
    l' ∈ foldr (fun y r => (permutationsAux2 t ts r y id).2) r L ↔
      l' ∈ r ∨ ∃ l₁ l₂, l₁ ++ l₂ ∈ L ∧ l₂ ≠ [] ∧ l' = l₁ ++ t :: l₂ ++ ts := by
  have :
    (∃ a : List α,
        a ∈ L ∧ ∃ l₁ l₂ : List α, ¬l₂ = nil ∧ a = l₁ ++ l₂ ∧ l' = l₁ ++ t :: (l₂ ++ ts)) ↔
      ∃ l₁ l₂ : List α, ¬l₂ = nil ∧ l₁ ++ l₂ ∈ L ∧ l' = l₁ ++ t :: (l₂ ++ ts) :=
    ⟨fun ⟨_, aL, l₁, l₂, l0, e, h⟩ => ⟨l₁, l₂, l0, e ▸ aL, h⟩, fun ⟨l₁, l₂, l0, aL, h⟩ =>
      ⟨_, aL, l₁, l₂, l0, rfl, h⟩⟩
  

Proof state:
α : Type u_1
β : Type u_2
t : α
ts : List α
r L : List (List α)
l' : List α
this :
  (∃ a, a ∈ L ∧ ∃ l₁ l₂, ¬l₂ = [] ∧ a = l₁ ++ l₂ ∧ l' = l₁ ++ t :: (l₂ ++ ts)) ↔
    ∃ l₁ l₂, ¬l₂ = [] ∧ l₁ ++ l₂ ∈ L ∧ l' = l₁ ++ t :: (l₂ ++ ts)
⊢ l' ∈ foldr (fun y r => (permutationsAux2 t ts r y id).2) r L ↔
    l' ∈ r ∨ ∃ l₁ l₂, l₁ ++ l₂ ∈ L ∧ l₂ ≠ [] ∧ l' = l₁ ++ t :: l₂ ++ ts

Next tactic:
rw [foldr_permutationsAux2]
theorem mem_foldr_permutationsAux2 {t : α} {ts : List α} {r L : List (List α)} {l' : List α} :
    l' ∈ foldr (fun y r => (permutationsAux2 t ts r y id).2) r L ↔
      l' ∈ r ∨ ∃ l₁ l₂, l₁ ++ l₂ ∈ L ∧ l₂ ≠ [] ∧ l' = l₁ ++ t :: l₂ ++ ts := by
  have :
    (∃ a : List α,
        a ∈ L ∧ ∃ l₁ l₂ : List α, ¬l₂ = nil ∧ a = l₁ ++ l₂ ∧ l' = l₁ ++ t :: (l₂ ++ ts)) ↔
      ∃ l₁ l₂ : List α, ¬l₂ = nil ∧ l₁ ++ l₂ ∈ L ∧ l' = l₁ ++ t :: (l₂ ++ ts) :=
    ⟨fun ⟨_, aL, l₁, l₂, l0, e, h⟩ => ⟨l₁, l₂, l0, e ▸ aL, h⟩, fun ⟨l₁, l₂, l0, aL, h⟩ =>
      ⟨_, aL, l₁, l₂, l0, rfl, h⟩⟩
  rw [foldr_permutationsAux2]
  

Proof state:
α : Type u_1
β : Type u_2
t : α
ts : List α
r L : List (List α)
l' : List α
this :
  (∃ a, a ∈ L ∧ ∃ l₁ l₂, ¬l₂ = [] ∧ a = l₁ ++ l₂ ∧ l' = l₁ ++ t :: (l₂ ++ ts)) ↔
    ∃ l₁ l₂, ¬l₂ = [] ∧ l₁ ++ l₂ ∈ L ∧ l' = l₁ ++ t :: (l₂ ++ ts)
⊢ l' ∈ (List.bind L fun y => (permutationsAux2 t ts [] y id).2) ++ r ↔
    l' ∈ r ∨ ∃ l₁ l₂, l₁ ++ l₂ ∈ L ∧ l₂ ≠ [] ∧ l' = l₁ ++ t :: l₂ ++ ts

Next tactic:
simp only [mem_permutationsAux2', ← this, or_comm, and_left_comm, mem_append, mem_bind,
    append_assoc, cons_append, exists_prop]
theorem length_foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) :
    length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) =
      sum (map length L) + length r :=
  by 

Proof state:
α : Type u_1
β : Type u_2
t : α
ts : List α
r L : List (List α)
⊢ length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = sum (map length L) + length r

Next tactic:
simp [foldr_permutationsAux2, (· ∘ ·), length_permutationsAux2]
theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n)
    (H : ∀ l ∈ L, length l = n) :
    length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by
  

Proof state:
α : Type u_1
β : Type u_2
t : α
ts : List α
r L : List (List α)
n : ℕ
H : ∀ (l : List α), l ∈ L → length l = n
⊢ length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r

Next tactic:
rw [length_foldr_permutationsAux2, (_ : List.sum (map length L) = n * length L)]
theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n)
    (H : ∀ l ∈ L, length l = n) :
    length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by
  rw [length_foldr_permutationsAux2, (_ : List.sum (map length L) = n * length L)]
  

Proof state:
α : Type u_1
β : Type u_2
t : α
ts : List α
r L : List (List α)
n : ℕ
H : ∀ (l : List α), l ∈ L → length l = n
⊢ sum (map length L) = n * length L

Next tactic:
induction' L with l L ih
theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n)
    (H : ∀ l ∈ L, length l = n) :
    length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by
  rw [length_foldr_permutationsAux2, (_ : List.sum (map length L) = n * length L)]
  induction' L with l L ih
  · 

Proof state:
case nil
α : Type u_1
β : Type u_2
t : α
ts : List α
r : List (List α)
n : ℕ
H : ∀ (l : List α), l ∈ [] → length l = n
⊢ sum (map length []) = n * length []

Next tactic:
simp
theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n)
    (H : ∀ l ∈ L, length l = n) :
    length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by
  rw [length_foldr_permutationsAux2, (_ : List.sum (map length L) = n * length L)]
  induction' L with l L ih
  · simp
  

Proof state:
case cons
α : Type u_1
β : Type u_2
t : α
ts : List α
r : List (List α)
n : ℕ
l : List α
L : List (List α)
ih : (∀ (l : List α), l ∈ L → length l = n) → sum (map length L) = n * length L
H : ∀ (l_1 : List α), l_1 ∈ l :: L → length l_1 = n
⊢ sum (map length (l :: L)) = n * length (l :: L)

Next tactic:
have sum_map : sum (map length L) = n * length L := ih fun l m => H l (mem_cons_of_mem _ m)
theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n)
    (H : ∀ l ∈ L, length l = n) :
    length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by
  rw [length_foldr_permutationsAux2, (_ : List.sum (map length L) = n * length L)]
  induction' L with l L ih
  · simp
  have sum_map : sum (map length L) = n * length L := ih fun l m => H l (mem_cons_of_mem _ m)
  

Proof state:
case cons
α : Type u_1
β : Type u_2
t : α
ts : List α
r : List (List α)
n : ℕ
l : List α
L : List (List α)
ih : (∀ (l : List α), l ∈ L → length l = n) → sum (map length L) = n * length L
H : ∀ (l_1 : List α), l_1 ∈ l :: L → length l_1 = n
sum_map : sum (map length L) = n * length L
⊢ sum (map length (l :: L)) = n * length (l :: L)

Next tactic:
have length_l : length l = n := H _ (mem_cons_self _ _)
theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n)
    (H : ∀ l ∈ L, length l = n) :
    length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by
  rw [length_foldr_permutationsAux2, (_ : List.sum (map length L) = n * length L)]
  induction' L with l L ih
  · simp
  have sum_map : sum (map length L) = n * length L := ih fun l m => H l (mem_cons_of_mem _ m)
  have length_l : length l = n := H _ (mem_cons_self _ _)
  

Proof state:
case cons
α : Type u_1
β : Type u_2
t : α
ts : List α
r : List (List α)
n : ℕ
l : List α
L : List (List α)
ih : (∀ (l : List α), l ∈ L → length l = n) → sum (map length L) = n * length L
H : ∀ (l_1 : List α), l_1 ∈ l :: L → length l_1 = n
sum_map : sum (map length L) = n * length L
length_l : length l = n
⊢ sum (map length (l :: L)) = n * length (l :: L)

Next tactic:
simp [sum_map, length_l, mul_add, add_comm, mul_succ]
@[simp]
theorem permutationsAux_nil (is : List α) : permutationsAux [] is = [] := by
  

Proof state:
α : Type u_1
β : Type u_2
is : List α
⊢ permutationsAux [] is = []

Next tactic:
rw [permutationsAux, permutationsAux.rec]
@[simp]
theorem permutationsAux_cons (t : α) (ts is : List α) :
    permutationsAux (t :: ts) is =
      foldr (fun y r => (permutationsAux2 t ts r y id).2) (permutationsAux ts (t :: is))
        (permutations is) :=
  by 

Proof state:
α : Type u_1
β : Type u_2
t : α
ts is : List α
⊢ permutationsAux (t :: ts) is =
    foldr (fun y r => (permutationsAux2 t ts r y id).2) (permutationsAux ts (t :: is)) (permutations is)

Next tactic:
rw [permutationsAux, permutationsAux.rec]
@[simp]
theorem permutationsAux_cons (t : α) (ts is : List α) :
    permutationsAux (t :: ts) is =
      foldr (fun y r => (permutationsAux2 t ts r y id).2) (permutationsAux ts (t :: is))
        (permutations is) :=
  by rw [permutationsAux, permutationsAux.rec]; 

Proof state:
α : Type u_1
β : Type u_2
t : α
ts is : List α
⊢ foldr (fun y r => (permutationsAux2 t ts r y id).2)
      (permutationsAux.rec (fun x => [])
        (fun t ts is IH1 IH2 => foldr (fun y r => (permutationsAux2 t ts r y id).2) IH1 (is :: IH2)) ts (t :: is))
      (is ::
        permutationsAux.rec (fun x => [])
          (fun t ts is IH1 IH2 => foldr (fun y r => (permutationsAux2 t ts r y id).2) IH1 (is :: IH2)) is []) =
    foldr (fun y r => (permutationsAux2 t ts r y id).2)
      (permutationsAux.rec (fun x => [])
        (fun t ts is IH1 IH2 => foldr (fun y r => (permutationsAux2 t ts r y id).2) IH1 (is :: IH2)) ts (t :: is))
      (permutations is)

Next tactic:
rfl
@[simp]
theorem permutations_nil : permutations ([] : List α) = [[]] := by
  

Proof state:
α : Type u_1
β : Type u_2
⊢ permutations [] = [[]]

Next tactic:
rw [permutations, permutationsAux_nil]
theorem map_permutationsAux (f : α → β) :
    ∀ ts is :
    List α, map (map f) (permutationsAux ts is) = permutationsAux (map f ts) (map f is) := by
  

Proof state:
α : Type u_1
β : Type u_2
f : α → β
⊢ ∀ (ts is : List α), map (map f) (permutationsAux ts is) = permutationsAux (map f ts) (map f is)

Next tactic:
refine' permutationsAux.rec (by simp) _
theorem map_permutationsAux (f : α → β) :
    ∀ ts is :
    List α, map (map f) (permutationsAux ts is) = permutationsAux (map f ts) (map f is) := by
  refine' permutationsAux.rec (by 

Proof state:
α : Type u_1
β : Type u_2
f : α → β
⊢ ∀ (is : List α), map (map f) (permutationsAux [] is) = permutationsAux (map f []) (map f is)

Next tactic:
simp
theorem map_permutationsAux (f : α → β) :
    ∀ ts is :
    List α, map (map f) (permutationsAux ts is) = permutationsAux (map f ts) (map f is) := by
  refine' permutationsAux.rec (by simp) _
  

Proof state:
α : Type u_1
β : Type u_2
f : α → β
⊢ ∀ (t : α) (ts is : List α),
    map (map f) (permutationsAux ts (t :: is)) = permutationsAux (map f ts) (map f (t :: is)) →
      map (map f) (permutationsAux is []) = permutationsAux (map f is) (map f []) →
        map (map f) (permutationsAux (t :: ts) is) = permutationsAux (map f (t :: ts)) (map f is)

Next tactic:
introv IH1 IH2
theorem map_permutationsAux (f : α → β) :
    ∀ ts is :
    List α, map (map f) (permutationsAux ts is) = permutationsAux (map f ts) (map f is) := by
  refine' permutationsAux.rec (by simp) _
  introv IH1 IH2; 

Proof state:
α : Type u_1
β : Type u_2
f : α → β
t : α
ts is : List α
IH1 : map (map f) (permutationsAux ts (t :: is)) = permutationsAux (map f ts) (map f (t :: is))
IH2 : map (map f) (permutationsAux is []) = permutationsAux (map f is) (map f [])
⊢ map (map f) (permutationsAux (t :: ts) is) = permutationsAux (map f (t :: ts)) (map f is)

Next tactic:
rw [map] at IH2
theorem map_permutationsAux (f : α → β) :
    ∀ ts is :
    List α, map (map f) (permutationsAux ts is) = permutationsAux (map f ts) (map f is) := by
  refine' permutationsAux.rec (by simp) _
  introv IH1 IH2; rw [map] at IH2
  

Proof state:
α : Type u_1
β : Type u_2
f : α → β
t : α
ts is : List α
IH1 : map (map f) (permutationsAux ts (t :: is)) = permutationsAux (map f ts) (map f (t :: is))
IH2 : map (map f) (permutationsAux is []) = permutationsAux (map f is) []
⊢ map (map f) (permutationsAux (t :: ts) is) = permutationsAux (map f (t :: ts)) (map f is)

Next tactic:
simp only [foldr_permutationsAux2, map_append, map, map_map_permutationsAux2, permutations,
    bind_map, IH1, append_assoc, permutationsAux_cons, cons_bind, ← IH2, map_bind]
theorem map_permutations (f : α → β) (ts : List α) :
    map (map f) (permutations ts) = permutations (map f ts) := by
  

Proof state:
α : Type u_1
β : Type u_2
f : α → β
ts : List α
⊢ map (map f) (permutations ts) = permutations (map f ts)

Next tactic:
rw [permutations, permutations, map, map_permutationsAux, map]
theorem map_permutations' (f : α → β) (ts : List α) :
    map (map f) (permutations' ts) = permutations' (map f ts) := by
  

Proof state:
α : Type u_1
β : Type u_2
f : α → β
ts : List α
⊢ map (map f) (permutations' ts) = permutations' (map f ts)

Next tactic:
induction' ts with t ts ih <;> [rfl; simp [← ih, map_bind, ← map_map_permutations'Aux, bind_map]]
theorem map_permutations' (f : α → β) (ts : List α) :
    map (map f) (permutations' ts) = permutations' (map f ts) := by
  

Proof state:
α : Type u_1
β : Type u_2
f : α → β
ts : List α
⊢ map (map f) (permutations' ts) = permutations' (map f ts)

Next tactic:
induction' ts with t ts ih
theorem map_permutations' (f : α → β) (ts : List α) :
    map (map f) (permutations' ts) = permutations' (map f ts) := by
  induction' ts with t ts ih <;> [

Proof state:
case nil
α : Type u_1
β : Type u_2
f : α → β
⊢ map (map f) (permutations' []) = permutations' (map f [])

Next tactic:
rfl
theorem map_permutations' (f : α → β) (ts : List α) :
    map (map f) (permutations' ts) = permutations' (map f ts) := by
  induction' ts with t ts ih <;> [rfl; 

Proof state:
case cons
α : Type u_1
β : Type u_2
f : α → β
t : α
ts : List α
ih : map (map f) (permutations' ts) = permutations' (map f ts)
⊢ map (map f) (permutations' (t :: ts)) = permutations' (map f (t :: ts))

Next tactic:
simp [← ih, map_bind, ← map_map_permutations'Aux, bind_map]
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  

Proof state:
α : Type u_1
β : Type u_2
is is' ts : List α
⊢ permutationsAux (is ++ ts) is' =
    map (fun x => x ++ ts) (permutationsAux is is') ++ permutationsAux ts (reverse is ++ is')

Next tactic:
induction' is with t is ih generalizing is'
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  induction' is with t is ih generalizing is'; · 

Proof state:
case nil
α : Type u_1
β : Type u_2
ts is' : List α
⊢ permutationsAux ([] ++ ts) is' =
    map (fun x => x ++ ts) (permutationsAux [] is') ++ permutationsAux ts (reverse [] ++ is')

Next tactic:
simp
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  induction' is with t is ih generalizing is'; · simp
  

Proof state:
case cons
α : Type u_1
β : Type u_2
ts : List α
t : α
is : List α
ih :
  ∀ (is' : List α),
    permutationsAux (is ++ ts) is' =
      map (fun x => x ++ ts) (permutationsAux is is') ++ permutationsAux ts (reverse is ++ is')
is' : List α
⊢ permutationsAux (t :: is ++ ts) is' =
    map (fun x => x ++ ts) (permutationsAux (t :: is) is') ++ permutationsAux ts (reverse (t :: is) ++ is')

Next tactic:
simp only [foldr_permutationsAux2, ih, bind_map, cons_append, permutationsAux_cons, map_append,
    reverse_cons, append_assoc, singleton_append]
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  induction' is with t is ih generalizing is'; · simp
  simp only [foldr_permutationsAux2, ih, bind_map, cons_append, permutationsAux_cons, map_append,
    reverse_cons, append_assoc, singleton_append]
  

Proof state:
case cons
α : Type u_1
β : Type u_2
ts : List α
t : α
is : List α
ih :
  ∀ (is' : List α),
    permutationsAux (is ++ ts) is' =
      map (fun x => x ++ ts) (permutationsAux is is') ++ permutationsAux ts (reverse is ++ is')
is' : List α
⊢ (List.bind (permutations is') fun y => (permutationsAux2 t (is ++ ts) [] y id).2) ++
      (map (fun x => x ++ ts) (permutationsAux is (t :: is')) ++ permutationsAux ts (reverse is ++ t :: is')) =
    (List.bind (permutations is') fun a => map (fun x => x ++ ts) (permutationsAux2 t is [] a id).2) ++
      (map (fun x => x ++ ts) (permutationsAux is (t :: is')) ++ permutationsAux ts (reverse is ++ t :: ([] ++ is')))

Next tactic:
congr 2
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  induction' is with t is ih generalizing is'; · simp
  simp only [foldr_permutationsAux2, ih, bind_map, cons_append, permutationsAux_cons, map_append,
    reverse_cons, append_assoc, singleton_append]
  congr 2
  

Proof state:
case cons.e_a.e_b
α : Type u_1
β : Type u_2
ts : List α
t : α
is : List α
ih :
  ∀ (is' : List α),
    permutationsAux (is ++ ts) is' =
      map (fun x => x ++ ts) (permutationsAux is is') ++ permutationsAux ts (reverse is ++ is')
is' : List α
⊢ (fun y => (permutationsAux2 t (is ++ ts) [] y id).2) = fun a =>
    map (fun x => x ++ ts) (permutationsAux2 t is [] a id).2

Next tactic:
funext _
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  induction' is with t is ih generalizing is'; · simp
  simp only [foldr_permutationsAux2, ih, bind_map, cons_append, permutationsAux_cons, map_append,
    reverse_cons, append_assoc, singleton_append]
  congr 2
  funext _
  

Proof state:
case cons.e_a.e_b.h
α : Type u_1
β : Type u_2
ts : List α
t : α
is : List α
ih :
  ∀ (is' : List α),
    permutationsAux (is ++ ts) is' =
      map (fun x => x ++ ts) (permutationsAux is is') ++ permutationsAux ts (reverse is ++ is')
is' x✝ : List α
⊢ (permutationsAux2 t (is ++ ts) [] x✝ id).2 = map (fun x => x ++ ts) (permutationsAux2 t is [] x✝ id).2

Next tactic:
rw [map_permutationsAux2]
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  induction' is with t is ih generalizing is'; · simp
  simp only [foldr_permutationsAux2, ih, bind_map, cons_append, permutationsAux_cons, map_append,
    reverse_cons, append_assoc, singleton_append]
  congr 2
  funext _
  rw [map_permutationsAux2]
  

Proof state:
case cons.e_a.e_b.h
α : Type u_1
β : Type u_2
ts : List α
t : α
is : List α
ih :
  ∀ (is' : List α),
    permutationsAux (is ++ ts) is' =
      map (fun x => x ++ ts) (permutationsAux is is') ++ permutationsAux ts (reverse is ++ is')
is' x✝ : List α
⊢ (permutationsAux2 t (is ++ ts) [] x✝ id).2 = (permutationsAux2 t is [] x✝ fun x => x ++ ts).2

Next tactic:
simp (config := { singlePass := true }) only [← permutationsAux2_comp_append]
theorem permutationsAux_append (is is' ts : List α) :
    permutationsAux (is ++ ts) is' =
      (permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
  induction' is with t is ih generalizing is'; · simp
  simp only [foldr_permutationsAux2, ih, bind_map, cons_append, permutationsAux_cons, map_append,
    reverse_cons, append_assoc, singleton_append]
  congr 2
  funext _
  rw [map_permutationsAux2]
  simp (config := { singlePass := true }) only [← permutationsAux2_comp_append]
  

Proof state:
case cons.e_a.e_b.h
α : Type u_1
β : Type u_2
ts : List α
t : α
is : List α
ih :
  ∀ (is' : List α),
    permutationsAux (is ++ ts) is' =
      map (fun x => x ++ ts) (permutationsAux is is') ++ permutationsAux ts (reverse is ++ is')
is' x✝ : List α
⊢ (permutationsAux2 t [] [] x✝ fun x => id (x ++ (is ++ ts))).2 = (permutationsAux2 t [] [] x✝ fun x => x ++ is ++ ts).2

Next tactic:
simp only [id, append_assoc]
theorem permutations_append (is ts : List α) :
    permutations (is ++ ts) = (permutations is).map (· ++ ts) ++ permutationsAux ts is.reverse := by
  

Proof state:
α : Type u_1
β : Type u_2
is ts : List α
⊢ permutations (is ++ ts) = map (fun x => x ++ ts) (permutations is) ++ permutationsAux ts (reverse is)

Next tactic:
simp [permutations, permutationsAux_append]
/--
The `R`-linear equivalence between additive morphisms `A →+ B` and `ℕ`-linear morphisms `A →ₗ[ℕ] B`.
-/
@[simps]
def addMonoidHomLequivNat {A B : Type*} (R : Type*) [Semiring R] [AddCommMonoid A]
    [AddCommMonoid B] [Module R B] : (A →+ B) ≃ₗ[R] A →ₗ[ℕ] B
    where
  toFun := AddMonoidHom.toNatLinearMap
  invFun := LinearMap.toAddMonoidHom
  map_add' := by 

Proof state:
R✝ : Type u_1
R₁ : Type u_2
R₂ : Type u_3
R₃ : Type u_4
R₄ : Type u_5
S : Type u_6
K : Type u_7
K₂ : Type u_8
M : Type u_9
M' : Type u_10
M₁ : Type u_11
M₂ : Type u_12
M₃ : Type u_13
M₄ : Type u_14
N : Type u_15
N₂ : Type u_16
ι : Type u_17
V : Type u_18
V₂ : Type u_19
A : Type u_20
B : Type u_21
R : Type u_22
inst✝³ : Semiring R
inst✝² : AddCommMonoid A
inst✝¹ : AddCommMonoid B
inst✝ : Module R B
⊢ ∀ (x y : A →+ B), AddMonoidHom.toNatLinearMap (x + y) = AddMonoidHom.toNatLinearMap x + AddMonoidHom.toNatLinearMap y

Next tactic:
intros
/--
The `R`-linear equivalence between additive morphisms `A →+ B` and `ℕ`-linear morphisms `A →ₗ[ℕ] B`.
-/
@[simps]
def addMonoidHomLequivNat {A B : Type*} (R : Type*) [Semiring R] [AddCommMonoid A]
    [AddCommMonoid B] [Module R B] : (A →+ B) ≃ₗ[R] A →ₗ[ℕ] B
    where
  toFun := AddMonoidHom.toNatLinearMap
  invFun := LinearMap.toAddMonoidHom
  map_add' := by intros; 

Proof state:
R✝ : Type u_1
R₁ : Type u_2
R₂ : Type u_3
R₃ : Type u_4
R₄ : Type u_5
S : Type u_6
K : Type u_7
K₂ : Type u_8
M : Type u_9
M' : Type u_10
M₁ : Type u_11
M₂ : Type u_12
M₃ : Type u_13
M₄ : Type u_14
N : Type u_15
N₂ : Type u_16
ι : Type u_17
V : Type u_18
V₂ : Type u_19
A : Type u_20
B : Type u_21
R : Type u_22
inst✝³ : Semiring R
inst✝² : AddCommMonoid A
inst✝¹ : AddCommMonoid B
inst✝ : Module R B
x✝ y✝ : A →+ B
⊢ AddMonoidHom.toNatLinearMap (x✝ + y✝) = AddMonoidHom.toNatLinearMap x✝ + AddMonoidHom.toNatLinearMap y✝

Next tactic:
ext