PLFA agda exercises
---
title     : "Fresh: Choose fresh variable name"
permalink : /Fresh
---

## Imports

\begin{code}
module Fresh where
\end{code}

\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter; concat; length)
open import Data.Nat using (ℕ; zero; suc; _+_; _∸_; _≤_; _⊔_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax)
  renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Data.String as Str
import Collections

pattern [_]       w        =  w ∷ []
pattern [_,_]     w x      =  w ∷ x ∷ []
pattern [_,_,_]   w x y    =  w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z  =  w ∷ x ∷ y ∷ z ∷ []
\end{code}

\begin{code}
Id : Set
Id = String

open Collections (Id) (_≟_)

prime : Id → Id
prime x = x Str.++ "′"

++-identityʳ : ∀ (us : List Id) → us ++ [] ≡ us
++-identityʳ []        =  refl
++-identityʳ (u ∷ us)  =  cong (u ∷_) (++-identityʳ us)

++-assoc : ∀ (us vs ws : List Id) →
  (us ++ vs) ++ ws ≡ us ++ (vs ++ ws)
++-assoc [] vs ws        =  refl
++-assoc (u ∷ us) vs ws  =  cong (u ∷_) (++-assoc us vs ws)

lemma : ∀ (us : List Id) (v w : Id)
  → w ∉ us → w ≢ v → w ∉ (us ++ [ v ])
lemma []       v w w∉ w≢ =  λ{ here → w≢ refl
                              ; (there ())
                              }
lemma (u ∷ us) v w w∉ w≢ =  λ{ here → w∉ here
                              ; (there y∈) → (lemma us v w (w∉ ∘ there) w≢) y∈
                              }

helper : ∀ (n : ℕ) (us vs xs : List Id) (w : Id)
  → w ∉ us → us ++ vs ≡ xs → ∃[ y ]( y ∉ xs)
helper n us []       xs w w∉ refl rewrite ++-identityʳ us = ⟨ w , w∉ ⟩
helper n us (v ∷ vs) xs w w∉ refl with w ≟ v
helper n us (v ∷ vs) xs w w∉ refl | no w≢
  =  helper n (us ++ [ v ]) vs xs w (lemma us v w w∉ w≢) (++-assoc us [ v ] vs)
helper (suc n) us (v ∷ vs) xs w w∉ refl | yes _
  =  helper n [] xs xs w (λ()) refl
helper zero us (v ∷ vs) xs w w∉ refl | yes _
  =  ⊥-elim impossible
  where postulate impossible : ⊥

fresh : List Id → Id → Id
fresh xs y = proj₁ (helper (length xs) [] xs xs y (λ()) refl)

fresh-lemma : ∀ (xs : List Id) (x : Id) → fresh xs x ∉ xs
fresh-lemma xs y = proj₂ (helper (length xs) [] xs xs y (λ()) refl)
\end{code}