{-# OPTIONS --without-K #-}
open import Type
open import Data.Nat
open import Data.Bit using (Bit)
open import Data.Bits using (Bits; RewireTbl)
open import Data.Fin using (Fin)
open import FunUniverse.Data
open import FunUniverse.Core
open import FunUniverse.Category
open import FunUniverse.Rewiring.Linear

module FunUniverse.Syntax {T : ★} (dataU : Universe T) where

open Universe dataU

infix 0 _`→_
data _`→_ : T → T → ★ where
    id        : ∀ {A} → A `→ A
    _∘_       : ∀ {A B C} → (B `→ C) → (A `→ B) → (A `→ C)

    fst       : ∀ {A B} → A `× B `→ A
    snd       : ∀ {A B} → A `× B `→ B
    first     : ∀ {A B C} → (A `→ C) → (A `× B) `→ (C `× B)
    second    : ∀ {A B C} → (B `→ C) → (A `× B) `→ (A `× C)
    swap      : ∀ {A B} → (A `× B) `→ (B `× A)
    assoc     : ∀ {A B C} → ((A `× B) `× C) `→ (A `× (B `× C))
    <_×_>     : ∀ {A B C D} → (A `→ C) → (B `→ D) → (A `× B) `→ (C `× D)
    <_,_>     : ∀ {A B C} → (A `→ B) → (A `→ C) → A `→ B `× C
    dup       : ∀ {A} → A `→ A `× A

    tt        : ∀ {_𝟙} → _𝟙 `→ `𝟙

    <[]>      : ∀ {_𝟙 A} → _𝟙 `→ `Vec A 0
    <∷>       : ∀ {n A} → (A `× `Vec A n) `→ `Vec A (1 + n)
    uncons    : ∀ {n A} → `Vec A (1 + n) `→ (A `× `Vec A n)

    bijFork   : ∀ {A B} (f g : A `→ B) → `Bit `× A `→ `Bit `× B
    cond      : ∀ {A} → `Bit `× A `× A `→ A
    fork      : ∀ {A B} (f g : A `→ B) → `Bit `× A `→ B

    <0b> <1b> : ∀ {_𝟙} → _𝟙 `→ `Bit

    xor       : ∀ {n} → Bits n → `Bits n `→ `Bits n
    rewire    : ∀ {i o} → (Fin o → Fin i) → `Bits i `→ `Bits o
    rewireTbl : ∀ {i o} → RewireTbl i o   → `Bits i `→ `Bits o

    <tt,id>   : ∀ {A} → A `→ `𝟙 `× A
    snd<tt,>  : ∀ {A} → `𝟙 `× A `→ A
    tt→[]     : ∀ {A} → `𝟙 `→ `Vec A 0
    []→tt     : ∀ {A} → `Vec A 0 `→ `𝟙

synU : FunUniverse T
synU = dataU , _`→_

synCat : Category _`→_
synCat = id , _∘_

synLin : LinRewiring synU
synLin = mk synCat first swap assoc <tt,id> snd<tt,> <_×_>
            second tt→[] []→tt <∷> uncons

synRewiring : Rewiring synU
synRewiring = mk synLin tt dup <[]> <_,_> fst snd rewire rewireTbl

synFork : HasFork synU
synFork = cond , fork

synOps : FunOps synU
synOps = mk synRewiring synFork <0b> <1b>