module WSLN.Fresh where

open import Prelude

open import WSLN.Index
open import WSLN.Atom

----------------------------------------------------------------------
-- Finite support structure
----------------------------------------------------------------------
record FiniteSupport (A : Set) : Set where
  infix 4 _#_
  field
    supp : A  Fset𝔸

  --Derived freshness relation
  _#_ : 𝔸  A  Set
  x # a = x  supp a

open FiniteSupport  ...  public

{-# DISPLAY FiniteSupport.supp _ a = supp a #-}

----------------------------------------------------------------------
-- Fresh atoms
----------------------------------------------------------------------
fresh :
  {A : Set}
   _ : FiniteSupport A 
  (a : A)
   ---------------------
  ∃[ x ] (x # a)

fresh a = (new (supp a) , new∉ (supp a))

----------------------------------------------------------------------
-- Decidability of the freshness relation
----------------------------------------------------------------------
#? :
 {A : Set}
  _ : FiniteSupport A 
 (x : 𝔸)
 (a : A)
  ---------------------
 Dec (x # a)

#? x a = dec∉ x (supp a)

----------------------------------------------------------------------
-- Freshness is a proposition
----------------------------------------------------------------------
instance
  isProp# :
    {A : Set}
     _ : FiniteSupport A 
    {x : 𝔸}
    {a : A}
     ---------------------
    isProp (x # a)
  !  isProp#  p q = !  isProp∉  p q

----------------------------------------------------------------------
-- Finite support for atoms and finite sets of atoms
----------------------------------------------------------------------
instance
  FiniteSupport𝔸 : FiniteSupport 𝔸
  supp  FiniteSupport𝔸  x =  x 

  FiniteSupportFset𝔸 : FiniteSupport (Fset𝔸)
  supp  FiniteSupportFset𝔸  xs = xs

#symm :
  {x y : 𝔸}
   -----------
  x # y  y # x

#symm (∉{} p) = ∉{} (≠𝔸symm p)

----------------------------------------------------------------------
-- Finite support for indices
----------------------------------------------------------------------
instance
  FiniteSupportFin : ∀{n}  FiniteSupport (Fin n)

  supp  FiniteSupportFin  i = 

----------------------------------------------------------------------
-- Finite support for cartesian products
----------------------------------------------------------------------
instance
  FiniteSupport× :
    {A B : Set}
     _ : FiniteSupport A 
     _ : FiniteSupport B 
     ---------------------
    FiniteSupport (A × B)

  supp  FiniteSupport×  (a , b) = supp a  supp b

----------------------------------------------------------------------
-- Finite support for lists
----------------------------------------------------------------------
module _ {A : Set}⦃ _ : FiniteSupport A  where
  suppList : List A  Fset𝔸

  suppList []        = 
  suppList (a :: as) = supp a  suppList as

  instance
    FiniteSupportList : FiniteSupport (List A)
    supp  FiniteSupportList  = suppList

{-# DISPLAY suppList xs = supp xs #-}

----------------------------------------------------------------------
-- Finite support for vectors
----------------------------------------------------------------------
module _ {A : Set}⦃ _ : FiniteSupport A  where
  suppVec : ∀{n}  Vec A n  Fset𝔸

  suppVec [] = 
  suppVec (x :: xs) = supp x  suppVec xs

  instance
    FiniteSupportVec :  {n}  FiniteSupport (Vec A n)
    supp  FiniteSupportVec  = suppVec

{-# DISPLAY suppVec xs = supp xs #-}

----------------------------------------------------------------------
-- Freshness for tuples of mutually distinct atoms
----------------------------------------------------------------------
infix 4 distinct_∉_
data distinct_∉_ : ∀{n}  Vec 𝔸 n  Fset𝔸  Set where
  -- Cf. A. Charguéraud, "The Locally Nameless Respesentation",
  -- J. Autom. Reasoning 49(2012) section 7.1
  ##◇ :
    {S : Fset𝔸}
     -------------
    distinct []  S
  ##:: :
    {n : }
    {xs : Vec 𝔸 n}
    {x : 𝔸}
    {S : Fset𝔸}
    (x∉S : x  S)
    (xs∉xS : distinct xs   x   S)
     --------------------------------
    distinct x :: xs  S

distinct{} :
  {n : }
  {xs : Vec 𝔸 n}
  {x : 𝔸}
  (_ : distinct xs   x )
   ------------------------
  x # xs
distinct⊆ :
  {n : }
  {xs : Vec 𝔸 n}
  {S S' : Fset𝔸}
  (_ : distinct xs  S')
  (_ : S  S')
   --------------------
  distinct xs  S

distinct{} ##◇ = ∉∅
distinct{}{x = x} (##::{x = x'} (∉{} p) p') =
  (∉{} (≠𝔸symm p)) ∉∪ (distinct{} (distinct⊆ p' ∈∪₂))

distinct⊆ ##◇ _ = ##◇
distinct⊆ (##:: p p') q =
  ##:: (⊆∉ q p) (distinct⊆ p' (∪⊆ id q))

distinct::₁ :
  {n : }
  {xs : Vec 𝔸 n}
  {x : 𝔸}
  {S : Fset𝔸}
  (_ : distinct x :: xs  S)
   -----------------------
  distinct xs  S

distinct::₁ (##:: _ p) = distinct⊆ p ∈∪₂

distinct::₂ :
  {n : }
  {xs : Vec 𝔸 n}
  {x : 𝔸}
  {S : Fset𝔸}
  (_ : distinct x :: xs  S)
   -----------------------
  x  S

distinct::₂ (##:: p _) = p

distinct::₃ :
  {n : }
  {xs : Vec 𝔸 n}
  {x : 𝔸}
  {S : Fset𝔸}
  (_ : distinct x :: xs  S)
   -----------------------
  x # xs

distinct::₃ {xs = []} _ = ∉∅
distinct::₃ {xs = x :: xs} (##:: p p') =
  distinct{} (distinct⊆ p' ∈∪₁)

-- Derived freshness relation for finitely supported types
module _  {A : Set}⦃ _ : FiniteSupport A  where
  infix 4 _##_
  _##_ : ∀{n}  Vec 𝔸 n  A  Set
  xs ## a = distinct xs  supp a

  infix 4 _#_#_
  _#_#_ : 𝔸  𝔸  A  Set
  x # y # a = y :: x :: [] ## a

  infix 4 _#_#_#_
  _#_#_#_ : 𝔸  𝔸  𝔸  A  Set
  x # y # z # a = z :: y :: x :: [] ## a