{-
This second-order term syntax was created from the following second-order syntax description:

syntax TLC | Ξ›

type
  N   : 0-ary
  _↣_ : 2-ary | r30
  πŸ™   : 0-ary
  _βŠ—_ : 2-ary | l40
  𝟘   : 0-ary
  _βŠ•_ : 2-ary | l30

term
  app   : Ξ± ↣ Ξ²  Ξ±  ->  Ξ² | _$_ l20
  lam   : Ξ±.Ξ²  ->  Ξ± ↣ Ξ² | Ζ›_ r10
  unit  : πŸ™
  pair  : Ξ±  Ξ²  ->  Ξ± βŠ— Ξ² | ⟨_,_⟩
  fst   : Ξ± βŠ— Ξ²  ->  Ξ±
  snd   : Ξ± βŠ— Ξ²  ->  Ξ²
  abort : 𝟘  ->  α
  inl   : Ξ±  ->  Ξ± βŠ• Ξ²
  inr   : Ξ²  ->  Ξ± βŠ• Ξ²
  case  : Ξ± βŠ• Ξ²  Ξ±.Ξ³  Ξ².Ξ³  ->  Ξ³
  ze    : N
  su    : N  ->  N
  nrec  : N  Ξ±  (Ξ±,N).Ξ±  ->  Ξ±

theory
  (Ζ›Ξ²) b : Ξ±.Ξ²  a : Ξ± |> app (lam(x.b[x]), a) = b[a]
  (Ζ›Ξ·) f : Ξ± ↣ Ξ²      |> lam (x. app(f, x))   = f
  (πŸ™Ξ·) u : πŸ™ |> u = unit
  (fΞ²) a : Ξ±  b : Ξ² |> fst (pair(a, b))      = a
  (sΞ²) a : Ξ±  b : Ξ² |> snd (pair(a, b))      = b
  (pΞ·) p : Ξ± βŠ— Ξ²    |> pair (fst(p), snd(p)) = p
  (𝟘η) e : 𝟘  c : α |> abort(e) = c
  (lΞ²) a : Ξ±   f : Ξ±.Ξ³  g : Ξ².Ξ³ |> case (inl(a), x.f[x], y.g[y])      = f[a]
  (rΞ²) b : Ξ²   f : Ξ±.Ξ³  g : Ξ².Ξ³ |> case (inr(b), x.f[x], y.g[y])      = g[b]
  (cΞ·) s : Ξ± βŠ• Ξ²  c : (Ξ± βŠ• Ξ²).Ξ³ |> case (s, x.c[inl(x)], y.c[inr(y)]) = c[s]
  (zeΞ²) z : Ξ±   s : (Ξ±,N).Ξ±        |> nrec (ze,       z, r m. s[r,m]) = z
  (suΞ²) z : Ξ±   s : (Ξ±,N).Ξ±  n : N |> nrec (su (n), z, r m. s[r,m]) = s[nrec (n, z, r m. s[r,m]), n]
  (ift) t f : Ξ± |> if (true, t, f) = t
  (iff) t f : Ξ± |> if (false, t, f) = f
-}


module TLC.Syntax where

open import SOAS.Common
open import SOAS.Context
open import SOAS.Variable
open import SOAS.Families.Core
open import SOAS.Construction.Structure
open import SOAS.ContextMaps.Inductive

open import SOAS.Metatheory.Syntax

open import TLC.Signature

private
  variable
    Ξ“ Ξ” Ξ  : Ctx
    Ξ± Ξ² Ξ³ : Ξ›T
    𝔛 : Familyβ‚›

-- Inductive term declaration
module Ξ›:Terms (𝔛 : Familyβ‚›) where

  data Ξ› : Familyβ‚› where
    var  : ℐ β‡ΎΜ£ Ξ›
    mvar : 𝔛 Ξ± Ξ  β†’ Sub Ξ› Ξ  Ξ“ β†’ Ξ› Ξ± Ξ“

    _$_   : Ξ› (Ξ± ↣ Ξ²) Ξ“ β†’ Ξ› Ξ± Ξ“ β†’ Ξ› Ξ² Ξ“
    Ζ›_    : Ξ› Ξ² (Ξ± βˆ™ Ξ“) β†’ Ξ› (Ξ± ↣ Ξ²) Ξ“
    unit  : Ξ› πŸ™ Ξ“
    ⟨_,_⟩ : Ξ› Ξ± Ξ“ β†’ Ξ› Ξ² Ξ“ β†’ Ξ› (Ξ± βŠ— Ξ²) Ξ“
    fst   : Ξ› (Ξ± βŠ— Ξ²) Ξ“ β†’ Ξ› Ξ± Ξ“
    snd   : Ξ› (Ξ± βŠ— Ξ²) Ξ“ β†’ Ξ› Ξ² Ξ“
    abort : Ξ› 𝟘 Ξ“ β†’ Ξ› Ξ± Ξ“
    inl   : Ξ› Ξ± Ξ“ β†’ Ξ› (Ξ± βŠ• Ξ²) Ξ“
    inr   : Ξ› Ξ² Ξ“ β†’ Ξ› (Ξ± βŠ• Ξ²) Ξ“
    case  : Ξ› (Ξ± βŠ• Ξ²) Ξ“ β†’ Ξ› Ξ³ (Ξ± βˆ™ Ξ“) β†’ Ξ› Ξ³ (Ξ² βˆ™ Ξ“) β†’ Ξ› Ξ³ Ξ“
    ze    : Ξ› N Ξ“
    su    : Ξ› N Ξ“ β†’ Ξ› N Ξ“
    nrec  : Ξ› N Ξ“ β†’ Ξ› Ξ± Ξ“ β†’ Ξ› Ξ± (Ξ± βˆ™ N βˆ™ Ξ“) β†’ Ξ› Ξ± Ξ“

  infixl 20 _$_
  infixr 10 Ζ›_

  open import SOAS.Metatheory.MetaAlgebra β…€F 𝔛

  Λᡃ : MetaAlg Ξ›
  Λᡃ = record
    { π‘Žπ‘™π‘” = Ξ» where
      (appβ‚’   β…‹ a , b)     β†’ _$_   a b
      (lamβ‚’   β…‹ a)         β†’ Ζ›_    a
      (unitβ‚’  β…‹ _)         β†’ unit
      (pairβ‚’  β…‹ a , b)     β†’ ⟨_,_⟩ a b
      (fstβ‚’   β…‹ a)         β†’ fst   a
      (sndβ‚’   β…‹ a)         β†’ snd   a
      (abortβ‚’ β…‹ a)         β†’ abort a
      (inlβ‚’   β…‹ a)         β†’ inl   a
      (inrβ‚’   β…‹ a)         β†’ inr   a
      (caseβ‚’  β…‹ a , b , c) β†’ case  a b c
      (zeβ‚’    β…‹ _)         β†’ ze
      (suβ‚’    β…‹ a)         β†’ su    a
      (nrecβ‚’  β…‹ a , b , c) β†’ nrec  a b c
    ; π‘£π‘Žπ‘Ÿ = var ; π‘šπ‘£π‘Žπ‘Ÿ = Ξ» π”ͺ mΞ΅ β†’ mvar π”ͺ (tabulate mΞ΅) }

  module Λᡃ = MetaAlg Λᡃ

  module _ {π’œ : Familyβ‚›}(π’œα΅ƒ : MetaAlg π’œ) where

    open MetaAlg π’œα΅ƒ

    π•€π•–π•ž : Ξ› β‡ΎΜ£ π’œ
    π•Š : Sub Ξ› Ξ  Ξ“ β†’ Ξ  ~[ π’œ ]↝ Ξ“
    π•Š (t β—‚ Οƒ) new = π•€π•–π•ž t
    π•Š (t β—‚ Οƒ) (old v) = π•Š Οƒ v
    π•€π•–π•ž (mvar π”ͺ mΞ΅) = π‘šπ‘£π‘Žπ‘Ÿ π”ͺ (π•Š mΞ΅)
    π•€π•–π•ž (var v) = π‘£π‘Žπ‘Ÿ v

    π•€π•–π•ž (_$_   a b)   = π‘Žπ‘™π‘” (appβ‚’   β…‹ π•€π•–π•ž a , π•€π•–π•ž b)
    π•€π•–π•ž (Ζ›_    a)     = π‘Žπ‘™π‘” (lamβ‚’   β…‹ π•€π•–π•ž a)
    π•€π•–π•ž  unit         = π‘Žπ‘™π‘” (unitβ‚’  β…‹ tt)
    π•€π•–π•ž (⟨_,_⟩ a b)   = π‘Žπ‘™π‘” (pairβ‚’  β…‹ π•€π•–π•ž a , π•€π•–π•ž b)
    π•€π•–π•ž (fst   a)     = π‘Žπ‘™π‘” (fstβ‚’   β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (snd   a)     = π‘Žπ‘™π‘” (sndβ‚’   β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (abort a)     = π‘Žπ‘™π‘” (abortβ‚’ β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (inl   a)     = π‘Žπ‘™π‘” (inlβ‚’   β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (inr   a)     = π‘Žπ‘™π‘” (inrβ‚’   β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (case  a b c) = π‘Žπ‘™π‘” (caseβ‚’  β…‹ π•€π•–π•ž a , π•€π•–π•ž b , π•€π•–π•ž c)
    π•€π•–π•ž  ze           = π‘Žπ‘™π‘” (zeβ‚’    β…‹ tt)
    π•€π•–π•ž (su    a)     = π‘Žπ‘™π‘” (suβ‚’    β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (nrec  a b c) = π‘Žπ‘™π‘” (nrecβ‚’  β…‹ π•€π•–π•ž a , π•€π•–π•ž b , π•€π•–π•ž c)

    π•€π•–π•žα΅ƒβ‡’ : MetaAlgβ‡’ Λᡃ π’œα΅ƒ π•€π•–π•ž
    π•€π•–π•žα΅ƒβ‡’ = record
      { βŸ¨π‘Žπ‘™π‘”βŸ© = Ξ»{ {t = t} β†’ βŸ¨π‘Žπ‘™π‘”βŸ© t }
      ; βŸ¨π‘£π‘Žπ‘ŸβŸ© = refl
      ; βŸ¨π‘šπ‘£π‘Žπ‘ŸβŸ© = Ξ»{ {π”ͺ = π”ͺ}{mΞ΅} β†’ cong (π‘šπ‘£π‘Žπ‘Ÿ π”ͺ) (dext (π•Š-tab mΞ΅)) }  }
      where
      open ≑-Reasoning
      βŸ¨π‘Žπ‘™π‘”βŸ© : (t : β…€ Ξ› Ξ± Ξ“) β†’ π•€π•–π•ž (Λᡃ.π‘Žπ‘™π‘” t) ≑ π‘Žπ‘™π‘” (⅀₁ π•€π•–π•ž t)
      βŸ¨π‘Žπ‘™π‘”βŸ© (appβ‚’   β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (lamβ‚’   β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (unitβ‚’  β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (pairβ‚’  β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (fstβ‚’   β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (sndβ‚’   β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (abortβ‚’ β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (inlβ‚’   β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (inrβ‚’   β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (caseβ‚’  β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (zeβ‚’    β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (suβ‚’    β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (nrecβ‚’  β…‹ _) = refl

      π•Š-tab : (mΞ΅ : Ξ  ~[ Ξ› ]↝ Ξ“)(v : ℐ Ξ± Ξ ) β†’ π•Š (tabulate mΞ΅) v ≑ π•€π•–π•ž (mΞ΅ v)
      π•Š-tab mΞ΅ new = refl
      π•Š-tab mΞ΅ (old v) = π•Š-tab (mΞ΅ ∘ old) v

    module _ (g : Ξ› β‡ΎΜ£ π’œ)(gᡃ⇒ : MetaAlgβ‡’ Λᡃ π’œα΅ƒ g) where

      open MetaAlgβ‡’ gᡃ⇒

      π•€π•–π•ž! : (t : Ξ› Ξ± Ξ“) β†’ π•€π•–π•ž t ≑ g t
      π•Š-ix : (mΞ΅ : Sub Ξ› Ξ  Ξ“)(v : ℐ Ξ± Ξ ) β†’ π•Š mΞ΅ v ≑ g (index mΞ΅ v)
      π•Š-ix (x β—‚ mΞ΅) new = π•€π•–π•ž! x
      π•Š-ix (x β—‚ mΞ΅) (old v) = π•Š-ix mΞ΅ v
      π•€π•–π•ž! (mvar π”ͺ mΞ΅) rewrite cong (π‘šπ‘£π‘Žπ‘Ÿ π”ͺ) (dext (π•Š-ix mΞ΅))
        = trans (sym βŸ¨π‘šπ‘£π‘Žπ‘ŸβŸ©) (cong (g ∘ mvar π”ͺ) (tab∘ixβ‰ˆid mΞ΅))
      π•€π•–π•ž! (var v) = sym βŸ¨π‘£π‘Žπ‘ŸβŸ©

      π•€π•–π•ž! (_$_ a b) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (Ζ›_ a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! unit = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (⟨_,_⟩ a b) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (fst a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (snd a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (abort a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (inl a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (inr a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (case a b c) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b | π•€π•–π•ž! c = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! ze = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (su a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (nrec a b c) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b | π•€π•–π•ž! c = sym βŸ¨π‘Žπ‘™π‘”βŸ©


-- Syntax instance for the signature
Ξ›:Syn : Syntax
Ξ›:Syn = record
  { β…€F = β…€F
  ; β…€:CS = β…€:CompatStr
  ; mvarα΅’ = Ξ›:Terms.mvar
  ; 𝕋:Init = Ξ» 𝔛 β†’ let open Ξ›:Terms 𝔛 in record
    { βŠ₯ = Ξ› ⋉ Λᡃ
    ; βŠ₯-is-initial = record { ! = Ξ»{ {π’œ ⋉ π’œα΅ƒ} β†’ π•€π•–π•ž π’œα΅ƒ ⋉ π•€π•–π•žα΅ƒβ‡’ π’œα΅ƒ }
    ; !-unique = Ξ»{ {π’œ ⋉ π’œα΅ƒ} (f ⋉ fᡃ⇒) {x = t} β†’ π•€π•–π•ž! π’œα΅ƒ f fᡃ⇒ t } } } }

-- Instantiation of the syntax and metatheory
open Syntax Ξ›:Syn public
open Ξ›:Terms public
open import SOAS.Families.Build public
open import SOAS.Syntax.Shorthands Λᡃ public
open import SOAS.Metatheory Ξ›:Syn public

-- Derived operations
true : Ξ› 𝔛 B Ξ“
true = inl unit
false : Ξ› 𝔛 B Ξ“
false = inr unit
if : Ξ› 𝔛 B Ξ“ β†’ Ξ› 𝔛 Ξ± Ξ“ β†’ Ξ› 𝔛 Ξ± Ξ“ β†’ Ξ› 𝔛 Ξ± Ξ“
if b t e = case b (Theory.π•¨π•œ _ t) (Theory.π•¨π•œ _ e)

plus : Ξ› 𝔛 (N ↣ N ↣ N) Ξ“
plus = Ζ› (Ζ› (nrec x₁ xβ‚€ (su xβ‚€)))

uncurry : Ξ› 𝔛 ((Ξ± ↣ Ξ² ↣ Ξ³) ↣ (Ξ± βŠ— Ξ²) ↣ Ξ³) Ξ“
uncurry = Ζ› Ζ› x₁ $ fst xβ‚€ $ snd xβ‚€