summaryrefslogtreecommitdiff
path: root/Nominal/LambdaCalculus/Preterms.lean
blob: c486a7e92686a60af56e74b1e977672fd60824f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import Mathlib
import Nominal.Permutations
import Nominal.Support
import Nominal.Helpers.CountableString

/-!
# λ-Preterms

As a practical example for nominal sets, this file defines λ-preterms (that is, λ-terms without α-equivalence).
-/

namespace Lambda

/-!
## Basic Syntax Definition

Define the AST and a parser for it.
-/
section Syntax

/-- We will use strings as the set of atoms, representing variable names. -/
def Var := String
  deriving DecidableEq, Countable, Infinite

/-- Basic λ-preterm definition.

We furthermore allow defining λ-terms as ⟫ t ⟪ with
  t, u ::= x | λ x y ..., t | t u,
where x, y, ... are variables. -/
inductive Preterm
  | var : Var → Preterm
  | abs : Var → Preterm → Preterm
  | app : Preterm → Preterm → Preterm
  deriving DecidableEq

open Lean Elab Meta

declare_syntax_cat lam

syntax ident : lam
syntax "(" lam ")" : lam
syntax:10 (name := stxabs) "λ " ident+ ", " lam : lam
syntax:45 lam:45 lam:46 : lam

partial def elabLam : Syntax → MetaM Expr
  | `(lam | $x:ident) => mkAppM ``Preterm.var #[mkStrLit x.getId.toString]
  | `(lam | ($t:lam)) => elabLam t
  | `(lam | $t:lam $u:lam) => do mkAppM ``Preterm.app #[← elabLam t, ← elabLam u]
  | `(lam | λ $xs:ident*, $t:lam) => do
    xs.foldrM (fun x t' => mkAppM ``Preterm.abs #[mkStrLit x.getId.toString, t']) (← elabLam t)
  | _ => throwUnsupportedSyntax

elab "⟫ " t:lam " ⟪" : term => elabLam t

example : ⟫ x y z ⟪ = ⟫ (x y) z ⟪ := by decide
example : ⟫ λ x, λ y, x ⟪ = ⟫ λ x y, x ⟪ := by decide

end Syntax

/-!
## Nominal Set Instance

The set of preterms forms a nominal set, where the permutation action just renames all occurrences of a variable.
-/
section NominalSet

namespace Preterm

private def rename (π : FPerm Var) : Preterm → Preterm
  | .var x => .var (π • x)
  | .abs x t => .abs (π • x) (rename π t)
  | .app t u => .app (rename π t) (rename π u)

private lemma one_rename (t : Preterm) : rename 1 t = t := by
  induction' t <;> all_goals simp [rename, *]

private lemma mul_rename (π τ : FPerm Var) (t : Preterm) : rename (π * τ) t = rename π (rename τ t) := by
  induction' t <;> all_goals simp [rename, mul_smul, *]

instance : PermSet Var Preterm where
  smul := rename
  one_smul := one_rename
  mul_smul := mul_rename

@[simp] lemma smul_var {π : FPerm Var} {x : Var} : π • Preterm.var x = Preterm.var (π • x) := rfl
@[simp] lemma smul_abs {π : FPerm Var} {x : Var} {t : Preterm} : π • Preterm.abs x t = Preterm.abs (π • x) (π • t) := rfl
@[simp] lemma smul_app {π : FPerm Var} {t u : Preterm} : π • Preterm.app t u = Preterm.app (π • t) (π • u) := rfl

private def aSupport : Preterm → Set Var
  | .var x => {x}
  | .abs x t => {x} ∪ aSupport t
  | .app t u => aSupport t ∪ aSupport u

instance : NominalSet Var Preterm where
  fin_supp t := by
    use aSupport t
    induction' t <;> all_goals expose_names
    · constructor
      · simp [PermSet.HasSupport, PermSet.fix, aSupport, PermSet.fix']
      · simp [aSupport]
    · constructor
      · intro π hπ
        simp only [PermSet.fix', smul_abs, Preterm.abs.injEq, Set.mem_setOf_eq]
        simp only [PermSet.fix, aSupport, Set.singleton_union, Set.mem_insert_iff, forall_eq_or_imp, Set.mem_setOf_eq] at hπ
        exact ⟨hπ.left, a_ih.left hπ.right⟩
      · simp [aSupport, Set.Finite.insert, a_ih]
    · constructor
      · intro π hπ
        simp only [PermSet.fix', smul_app, Preterm.app.injEq, Set.mem_setOf_eq]
        simp only [PermSet.fix, aSupport, Set.mem_union, Set.mem_setOf_eq] at hπ
        constructor
        · exact a_ih.left (fun x hx => hπ x (Or.inl hx))
        · exact a_ih_1.left (fun x hx => hπ x (Or.inr hx))
      · simp [aSupport, a_ih, a_ih_1]

end Preterm

end NominalSet

end Lambda