---
layout: default
title : "Setoid.Algebras.Basic module (Agda Universal Algebra Library)"
date : "2021-04-23"
author: "agda-algebras development team"
---
#### Basic definitions
This is the [Setoid.Algebras.Basic][] module of the [Agda Universal Algebra Library][].
<!--
```agda
{-# OPTIONS --cubical-compatible --exact-split --safe #-}
open import Overture using (π ; π₯ ; Signature )
module Setoid.Algebras.Basic {π : Signature π π₯} where
open import Agda.Primitive using ( _β_ ; lsuc ) renaming ( Set to Type )
open import Data.Product using ( _,_ ; Ξ£-syntax ) public
open import Function using ( _β_ ; _ββ_ ; Func ; _$_ )
open import Level using ( Level )
open import Relation.Binary using ( Setoid )
open import Relation.Binary.PropositionalEquality as β‘ using ( _β‘_ ; refl )
open import Overture using ( OperationSymbolsOf ; ArityOf )
open import Overture.Operations using ( Op )
open import Setoid.Signatures using ( β¨_β© )
private variable Ξ± Ο ΞΉ : Level
```
-->
```agda
ov : Level β Level
ov Ξ± = π β π₯ β lsuc Ξ±
```
#### Setoid Algebras
Here we define algebras over a setoid, instead of a mere type with no equivalence on it.
The operator `β¨_β©`{.AgdaFunction} that translates an ordinary signature into a
signature over a setoid domain β together with its companion `EqArgs`{.AgdaFunction}
β is defined in the signature-generic module [Setoid.Signatures][] and imported
here (see the import above). Each takes its own signature argument rather than
reading this module's `{π}`, so housing them in a non-parameterized module means
the unused `{π : Signature π π₯}` parameter of this module does not ride along as
an unsolvable metavariable at use sites. The `Interp`{.AgdaField} field of
`Algebra`{.AgdaRecord} applies the imported `β¨ π β©` to this module's signature `π`.
Because the carrier of `β¨ π β© Domain` is a `Ξ£`-type β an operation symbol paired with
its argument tuple β an `Interp`{.AgdaField} clause matches it as `(o , args)`, which
needs the pair constructor `_,_` in scope. We therefore re-export `_,_` and
`Ξ£-syntax`{.AgdaFunction} from this module (and hence from the `Setoid.Algebras` barrel),
so that pattern-matching such a carrier needs no separate `Data.Product` import β and no
longer trips the misleading "`β-Op` is not a constructor of the datatype β¦ `Ξ£`" error,
which points at the operation symbol rather than at the missing `_,_`.
```agda
open Func renaming ( to to _β¨$β©_ ; cong to βcong )
```
A setoid algebra is just like an algebra but we require that all basic operations
of the algebra respect the underlying setoid equality. The `Func` record packs a
function (`f`, aka apply, aka `_β¨$β©_`) with a proof (cong) that the function respects
equality.
```agda
record Algebra Ξ± Ο : Type (π β π₯ β lsuc (Ξ± β Ο)) where
field
Domain : Setoid Ξ± Ο
Interp : Func (β¨ π β© Domain) Domain
open Setoid Domain using ( _β_ )
β‘ββ : β{x}{y} β x β‘ y β x β y
β‘ββ refl = Setoid.refl Domain
open Algebra
```
The next three definitions are merely syntactic sugar that we sometimes use to make
the code more readable.
```agda
π»[_] : Algebra Ξ± Ο β Setoid Ξ± Ο
π»[ π¨ ] = Domain π¨
π[_] : Algebra Ξ± Ο β Type Ξ±
π[ π¨ ] = Setoid.Carrier π»[ π¨ ]
```
We use the ascii symbol `^` to define an infix function for operation-symbol
interpretation in an algebra.[^1]
```agda
_^_ : (f : OperationSymbolsOf π)(π¨ : Algebra Ξ± Ο) β Op (ArityOf π f) π[ π¨ ]
f ^ π¨ = Ξ» a β (Interp π¨) β¨$β© (f , a)
```
We previously used a unicode symbol for this purpose; the definition is preserved for
backward compatibility, but its use is deprecated in favor of the ascii version
above. See [ADR-002][] Β§7 for the rationale.
```agda
_Μ_ : (f : OperationSymbolsOf π)(π¨ : Algebra Ξ± Ο) β Op (ArityOf π f) π[ π¨ ]
f Μ π¨ = Ξ» a β (Interp π¨) β¨$β© (f , a)
{-# WARNING_ON_USAGE _Μ_
"The combining-caret notation `_Μ_` is deprecated as of v3.0 and will be removed
in v3.1. Use the ASCII `_^_` defined immediately above. See ADR-002 Β§7."
#-}
```
#### Smart constructors for concrete algebras
Authoring a concrete `Algebra`{.AgdaRecord} by hand means supplying the
`Interp`{.AgdaField} field as a `Func`{.AgdaRecord} `(β¨ π β© Domain) Domain`, whose
congruence proof must take apart the `Ξ£`/`EqArgs`{.AgdaFunction} encoding of `β¨ π β©`:
the clause `βcong {o , _} {.o , _} (refl , argsβ) = β¦` recurs verbatim in every such
algebra (it appears across `Examples.Setoid.*` and `Classical.Bundles.*`). The two
builders below package that destructuring once.
A *fully automatic* congruence is not derivable at this layer, and deliberately so.
Passing from the pointwise hypothesis `β i β u i β v i` to `f o u β f o v` is exactly an
application of function extensionality, which the Setoid development avoids on principle
and which is in any case unavailable under `--safe --cubical-compatible`.
So each constructor still requires a per-operation, pointwise congruence `cong-f`;
it removes only the `(refl , argsβ)` boilerplate, never the mathematical content.
`mkAlgebra`{.AgdaFunction} is the general builder. Given a carrier setoid `π`, an
interpretation `f` of each operation symbol, and a proof `cong-f` that every `f o`
respects pointwise setoid equality of its argument tuple, `mkAlgebra`{.AgdaFunction}
assembles the `Algebra`{.AgdaRecord}, discharging the
`{o , _} {.o , _} (refl , argsβ)` match internally.
```agda
module _ (π· : Setoid Ξ± Ο) where
open Setoid π· using (_β_) renaming (Carrier to D)
mkAlgebra :
(f : (o : OperationSymbolsOf π) β Op (ArityOf π o) D)
β (β o β {u v : ArityOf π o β D} β (β i β u i β v i) β f o u β f o v)
β Algebra Ξ± Ο
mkAlgebra f cong-f .Domain = π·
mkAlgebra f cong-f .Interp β¨$β© (o , args) = f o args
mkAlgebra f cong-f .Interp .βcong {o , _} {.o , _} (refl , argsβ) = cong-f o argsβ
```
`mkAlgebraβ`{.AgdaFunction} specialises `mkAlgebra`{.AgdaFunction} to a carrier whose
equality is propositional `_β‘_`. It takes a bare type `A`, builds `Domain = β‘.setoid A`
(a `Setoid Ξ± Ξ±`, so the result is `Algebra Ξ± Ξ±`), and asks for `cong-f` in pointwise `_β‘_`
form β e.g. `β‘.congβ` for a binary operation, as in the `ββΈ`-magma of
`Examples.Setoid.FreeMagma`.
```agda
mkAlgebraβ : (A : Type Ξ±)
(f : (o : OperationSymbolsOf π) β Op (ArityOf π o) A)
β (β o β {u v : ArityOf π o β A} β (β i β u i β‘ v i) β f o u β‘ f o v)
β Algebra Ξ± Ξ±
mkAlgebraβ A f cong-f = mkAlgebra (β‘.setoid A) f cong-f
```
Sometimes we want to extract the universe level of a given algebra or its carrier.
The following functions provide that information.
```agda
Level-of-Alg : {Ξ± Ο π π₯ : Level}{π : Signature π π₯} β Algebra Ξ± Ο β Level
Level-of-Alg {Ξ± = Ξ±}{Ο}{π}{π₯} _ = π β π₯ β lsuc (Ξ± β Ο)
Level-of-Carrier : {Ξ± Ο π π₯ : Level}{π : Signature π π₯} β Algebra Ξ± Ο β Level
Level-of-Carrier {Ξ± = Ξ±} _ = Ξ±
```
#### Level lifting setoid algebra types
```agda
module _ (π¨ : Algebra Ξ± Ο)(β : Level) where
open Algebra π¨ using () renaming ( Domain to A )
open Setoid A using (sym ; trans ) renaming ( Carrier to β£Aβ£ ; _β_ to _ββ_ ; refl to reflβ )
open Level
Lift-AlgΛ‘ : Algebra (Ξ± β β) Ο
Lift-AlgΛ‘ .Domain =
record { Carrier = Lift β β£Aβ£
; _β_ = Ξ» x y β lower x ββ lower y
; isEquivalence = record { refl = reflβ ; sym = sym ; trans = trans }
}
Lift-AlgΛ‘ .Interp β¨$β© (f , la) = lift $ (f ^ π¨) (lower β la)
Lift-AlgΛ‘ .Interp .βcong (refl , la=lb) = βcong (Interp π¨) (refl , la=lb)
Lift-AlgΚ³ : Algebra Ξ± (Ο β β)
Lift-AlgΚ³ .Domain =
record { Carrier = β£Aβ£
; _β_ = (Lift β) ββ _ββ_
; isEquivalence = record { refl = lift reflβ
; sym = lift β sym β lower
; trans = Ξ» x y β lift $ trans (lower x) (lower y)
}
}
Lift-AlgΚ³ .Interp β¨$β© (f , la) = (f ^ π¨) la
Lift-AlgΚ³ .Interp .βcong (refl , laβ‘lb) = lift $ βcong (Interp π¨) (β‘.refl , (lower β laβ‘lb))
Lift-Alg : (π¨ : Algebra Ξ± Ο)(ββ ββ : Level) β Algebra (Ξ± β ββ) (Ο β ββ)
Lift-Alg π¨ ββ = Lift-AlgΚ³ (Lift-AlgΛ‘ π¨ ββ)
```
--------------------------------
[^1]: The `_^_` symbol is definitionally identical to `_Μ_` and was introduced for grep-friendliness and to survive shell-pipeline tooling. New `Classical/` code uses `_^_` exclusively; existing `Setoid/` code may continue to use `_Μ_` until v3.1. See ADR-002 Β§7 for the rationale and per-tree policy.