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

syntax Lens | L

type
  S : 0-ary
  A : 0-ary

term
  get : S  ->  A
  put : S  A  ->  S

theory
  (PG) s : S  a : A   |> get (put (s, a))   = a
  (GP) s : S          |> put (s, get(s))    = s
  (PP) s : S  a b : A |> put (put(s, a), b) = put (s, a)
-}


module Lens.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 Lens.Signature

private
  variable
    Ξ“ Ξ” Ξ  : Ctx
    Ξ± : LT
    𝔛 : Familyβ‚›

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

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

    get : L S Ξ“ β†’ L A Ξ“
    put : L S Ξ“ β†’ L A Ξ“ β†’ L S Ξ“



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

  Lᡃ : MetaAlg L
  Lᡃ = record
    { π‘Žπ‘™π‘” = Ξ» where
      (getβ‚’ β…‹ a)     β†’ get a
      (putβ‚’ β…‹ a , b) β†’ put a b
    ; π‘£π‘Žπ‘Ÿ = var ; π‘šπ‘£π‘Žπ‘Ÿ = Ξ» π”ͺ mΞ΅ β†’ mvar π”ͺ (tabulate mΞ΅) }

  module Lᡃ = MetaAlg Lᡃ

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

    open MetaAlg π’œα΅ƒ

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

    π•€π•–π•ž (get a)   = π‘Žπ‘™π‘” (getβ‚’ β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (put a b) = π‘Žπ‘™π‘” (putβ‚’ β…‹ π•€π•–π•ž a , π•€π•–π•ž b)

    π•€π•–π•žα΅ƒβ‡’ : MetaAlgβ‡’ Lᡃ π’œα΅ƒ π•€π•–π•ž
    π•€π•–π•žα΅ƒβ‡’ = record
      { βŸ¨π‘Žπ‘™π‘”βŸ© = Ξ»{ {t = t} β†’ βŸ¨π‘Žπ‘™π‘”βŸ© t }
      ; βŸ¨π‘£π‘Žπ‘ŸβŸ© = refl
      ; βŸ¨π‘šπ‘£π‘Žπ‘ŸβŸ© = Ξ»{ {π”ͺ = π”ͺ}{mΞ΅} β†’ cong (π‘šπ‘£π‘Žπ‘Ÿ π”ͺ) (dext (π•Š-tab mΞ΅)) }  }
      where
      open ≑-Reasoning
      βŸ¨π‘Žπ‘™π‘”βŸ© : (t : β…€ L Ξ± Ξ“) β†’ π•€π•–π•ž (Lᡃ.π‘Žπ‘™π‘” t) ≑ π‘Žπ‘™π‘” (⅀₁ π•€π•–π•ž t)
      βŸ¨π‘Žπ‘™π‘”βŸ© (getβ‚’ β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (putβ‚’ β…‹ _) = refl

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

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

      open MetaAlgβ‡’ gᡃ⇒

      π•€π•–π•ž! : (t : L Ξ± Ξ“) β†’ π•€π•–π•ž t ≑ g t
      π•Š-ix : (mΞ΅ : Sub L Ξ  Ξ“)(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 βŸ¨π‘£π‘Žπ‘ŸβŸ©

      π•€π•–π•ž! (get a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (put a b) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b = sym βŸ¨π‘Žπ‘™π‘”βŸ©


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

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