{-# OPTIONS --safe #-}
module Cubical.Algebra.Semigroup.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Equiv.HalfAdjoint
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Univalence
open import Cubical.Foundations.Transport
open import Cubical.Foundations.SIP

open import Cubical.Data.Sigma

open import Cubical.Reflection.RecordEquiv
open import Cubical.Reflection.StrictEquiv

open import Cubical.Displayed.Base
open import Cubical.Displayed.Auto
open import Cubical.Displayed.Record
open import Cubical.Displayed.Universe

open Iso


private
  variable
     : Level

-- Semigroups as a record, inspired by the Agda standard library:
--
--  https://github.com/agda/agda-stdlib/blob/master/src/Algebra/Bundles.agda#L48
--  https://github.com/agda/agda-stdlib/blob/master/src/Algebra/Structures.agda#L50
--
-- Note that as we are using Path for all equations the IsMagma record
-- would only contain isSet A if we had it.
record IsSemigroup {A : Type } (_·_ : A  A  A) : Type  where
  no-eta-equality
  constructor issemigroup

  field
    is-set : isSet A
    assoc  : (x y z : A)  x · (y · z)  (x · y) · z

unquoteDecl IsSemigroupIsoΣ = declareRecordIsoΣ IsSemigroupIsoΣ (quote IsSemigroup)

record SemigroupStr (A : Type ) : Type  where

  constructor semigroupstr

  field
    _·_         : A  A  A
    isSemigroup : IsSemigroup _·_

  infixl 7 _·_

  open IsSemigroup isSemigroup public

Semigroup :    Type (ℓ-suc )
Semigroup  = TypeWithStr  SemigroupStr

semigroup : (A : Type ) (_·_ : A  A  A) (h : IsSemigroup _·_)  Semigroup 
semigroup A _·_ h = A , semigroupstr _·_ h

record IsSemigroupEquiv {A : Type } {B : Type }
  (M : SemigroupStr A) (e : A  B) (N : SemigroupStr B)
  : Type 
  where

  -- Shorter qualified names
  private
    module M = SemigroupStr M
    module N = SemigroupStr N

  field
    isHom : (x y : A)  equivFun e (x M.· y)  equivFun e x N.· equivFun e y

open SemigroupStr
open IsSemigroup
open IsSemigroupEquiv

SemigroupEquiv : (M N : Semigroup )  Type 
SemigroupEquiv M N = Σ[ e   M    N  ] IsSemigroupEquiv (M .snd) e (N .snd)

isPropIsSemigroup : {A : Type } (_·_ : A  A  A)  isProp (IsSemigroup _·_)
isPropIsSemigroup _·_ =
  isOfHLevelRetractFromIso 1 IsSemigroupIsoΣ
    (isPropΣ
      isPropIsSet
       isSetA  isPropΠ3 λ _ _ _  isSetA _ _))

𝒮ᴰ-Semigroup : DUARel (𝒮-Univ ) SemigroupStr 
𝒮ᴰ-Semigroup =
  𝒮ᴰ-Record (𝒮-Univ _) IsSemigroupEquiv
    (fields:
      data[ _·_  autoDUARel _ _  isHom ]
      prop[ isSemigroup   _ _  isPropIsSemigroup _) ])

SemigroupPath : (M N : Semigroup )  SemigroupEquiv M N  (M  N)
SemigroupPath =  𝒮ᴰ-Semigroup .UARel.ua