Skip to content
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ New modules

* `Data.List.Relation.Binary.Permutation.Declarative{.Properties}` for the least congruence on `List` making `_++_` commutative, and its equivalence with the `Setoid` definition.

* `Relation.Binary.Construct.SetoidFromPartialSetoid`.

Additions to existing modules
-----------------------------

Expand Down Expand Up @@ -99,6 +101,11 @@ Additions to existing modules
updateAt (padRight m≤n x xs) (inject≤ i m≤n) f ≡ padRight m≤n x (updateAt xs i f)
```

* In `Relation.Binary.Definitions`
```agda
Defined : Rel A ℓ → A → Set ℓ
```

* In `Relation.Nullary.Negation.Core`
```agda
¬¬-η : A → ¬ ¬ A
Expand Down
65 changes: 65 additions & 0 deletions src/Relation/Binary/Construct/Kernel.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Equaliser of a kernel pair in Setoid
------------------------------------------------------------------------

open import Relation.Binary.Bundles using (PartialSetoid; Setoid)

module Relation.Binary.Construct.Kernel
{a i ℓ} {I : Set i}
(S : PartialSetoid a ℓ) (let module S = PartialSetoid S)
(f g : I → S.Carrier)
where

open import Function.Base using (id; _∘_; _on_)
open import Level using (Level; _⊔_)
open import Relation.Binary.Core using (Rel)
open import Relation.Binary.Definitions using (Defined)
open import Relation.Binary.Structures using (IsEquivalence)
open import Relation.Binary.Morphism.Structures
using (IsRelHomomorphism; IsRelMonomorphism)

import Relation.Binary.Properties.PartialSetoid S as Properties


------------------------------------------------------------------------
-- Definitions

record Carrier : Set (a ⊔ i ⊔ ℓ) where
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not happy with this record being called Carrier and its 'carrier' field being called h. To me, Carrier will always mean the underlying type of something Setoid-based. So re-using that name confounds expectations.

It feels like Carrier is instead some kind of Index-type with a distinguished point h.

Copy link
Contributor Author

@jamesmckinna jamesmckinna Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not happy with this record being called Carrier and its 'carrier' field being called h. To me, Carrier will always mean the underlying type of something Setoid-based. So re-using that name confounds expectations.

@JacquesCarette I'm reluctant to antagonise the collective wisdom of McMaster any more than I already seem to be doing over order-theoretic concepts, so I'll try to restate my position FTR, and then happily let others decide what becomes of this:

  • one of the end products of this PR is precisely to establish Carrier (the record type) as the Carrier (field value) of "something Setoid based", namely the bundle defining the 'subset on which f and g equalise'
  • it's clear you don't like the pun; fair enough, but I would never expect this type to be explicitly exported, except through the Setoid interface (cf. [DRY] what's the best way to publicly re-export properties/structure? #2391 ); I guess I could make it private, to improve matters? Alternatively, it could indeed be renamed, but as I say, I regard it as an abstract data type, existing solely to be a choice of domain for the isRelMonomorphism definition... viz. as a way of speaking about 'the subset on which f and g equalise'
  • it's conventional, given f, and g defining some diagram (here: a parallel pair with domain I, as per the 'sub-thing as given by a map on indices' construction, to have h, or perhaps better here, k (for Kernel, except that old-timey category theory books tend to use h for the universal equalising map, and k for the corresponding coequalising map in a coequaliser diagram) define the (appropriate) unique mediating morphism (I won't debate uniqueness or otherwise here, given higher-minded, and higher-dimensional, sensitivities about 'uniqueness up to what?'); given the way that field name become projection functions, that, again precisely, establishes h, or whatever we end up calling it, as a function of type Carrier → I, and again, conventionally, in such a way as to fit the diagram of parallel arrows f, g...
  • I've proposed/queried elsewhere the use of a standardised idiom for describing the eventual map ι : Carrier → S.Carrier, as, again precisely, corresponding to 'the injection into S of the subset on which f and g equalise', but again, the actual name seems really neither here nor there, but for the fact that, again from the public exports, h is never again mentioned (so its name is similarly immaterial/abstract)

I'd be quite happy to say 'puns considered harmful', and rename everything, but for the fact that these objects/constructions giving rise to the (intended for public export) definitions

  • _≈_
  • isEquivalence
  • setoid
  • isRelMonomorphism

do all need to be named. Perhaps it was failure of imagination on my part not to be able to come up with better ones, but in the end, I thought, it turns out mistakenly, that the ones I chose, for the reasons above, made the best 'fit'.

HTH!

It feels like Carrier is instead some kind of Index-type with a distinguished point h.

See above: h defines, as a projection, a function from Carrier to I.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making it private would go part of the way, for sure. Some puns I like, but somehow not this one.

The argument "establishing this as the Carrier of ..." doesn't go very far, as it could be extended to so many more things.

Have you considered Equalizer as the name? EqualAt, if we want a less fancy name?


field
h : I
refl : (f h) S.≈ (g h)

ι : S.Carrier
ι = f h


open Carrier public using (ι)

_≈_ : Rel Carrier _
_≈_ = S._≈_ on ι

-- Structure

isEquivalence : IsEquivalence _≈_
isEquivalence = record
{ refl = λ {x = x} → Properties.partial-reflˡ (Carrier.refl x)
; sym = S.sym
; trans = S.trans
}

-- Bundle

setoid : Setoid _ _
setoid = record { isEquivalence = isEquivalence }

-- Monomorphism

isRelHomomorphism : IsRelHomomorphism _≈_ S._≈_ ι
isRelHomomorphism = record { cong = id }

isRelMonomorphism : IsRelMonomorphism _≈_ S._≈_ ι
isRelMonomorphism = record { isHomomorphism = isRelHomomorphism ; injective = id }

58 changes: 58 additions & 0 deletions src/Relation/Binary/Construct/SetoidFromPartialSetoid.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Conversion of a PartialSetoid into a Setoid
------------------------------------------------------------------------

open import Relation.Binary.Bundles using (PartialSetoid; Setoid)

module Relation.Binary.Construct.SetoidFromPartialSetoid
{a ℓ} (S : PartialSetoid a ℓ) where

open import Function.Base using (id; _on_)
open import Level using (_⊔_)
open import Relation.Binary.Core using (Rel)
open import Relation.Binary.Definitions using (Defined)
open import Relation.Binary.Structures using (IsEquivalence)
open import Relation.Binary.Morphism.Structures
using (IsRelHomomorphism; IsRelMonomorphism)

private
module S = PartialSetoid S


------------------------------------------------------------------------
-- Definitions

record Carrier : Set (a ⊔ ℓ) where
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say that I expected the carrier to be called Carrier (and not ι) with the record called something like 'Reflective' or some such.

Thinking some more, I think having a definition for Defined x (expanding to x S.≈ x) might make the overall definition more perspicuous.

Copy link
Contributor Author

@jamesmckinna jamesmckinna Sep 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So...

  • Carrier (capitalised) is the carrier type; did you envisage carrier (lower-case) for the name of its inhabitant?
    I was motivated by my proposal under Substructures and quotients in the Algebra.* hierarchy #1899 to have a standardised name which then becomes the underlying function of the homo-/mono-morphism injecting Carrier into S.Carrier... but part of my thinking was also that the record itself doesn't merit an 'interesting' name... because it should only be exposed through its Setoid API, when it would moreover, again receive the name Carrier... (and be renamed, presumably, at any client use-site, if needed)
  • adding Defined sounds a good suggestion for Relation.Binary.Definitions... DRY says we should then redefine Reflexive in terms of it?

On naming, I think I was struck looking back over #2071 that the carrier type of the symmetric interior is given an 'interesting'/'informative' name, when in fact that's another case (I now think), where the record type is a concrete implementation detail which should only really be accessed/accessible via the API for the Construct being defined... esp. given that the module import path already cues the construction as that of the symmetric interior...

UPDATED: I've gone back over that last paragraph, and it doesn't any longer make sense!? Sorry for the noise!

Let me retry :
#2071 defines a construction on binary relations, not on types, whereas Carrier constructs a type towards building a Setoid, so it's not obvious that it belongs under Construct?

The operating construct on binary relations involved here is simply _on_, but I'd hesitate before putting the derived constructions as Properties of Relation.Binary.Construct.On...?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

D'oh!?

I've ended up defining
subset = equaliser of kernel pair
for a/the special case of the 'inclusion'...

So it is probably better to refactor this as
kernel pair of arbitrary function (Fam again!?), and then specialise that at id?

Or: take a breath and sit on my hands for a bit...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good realization - I certainly had not spotted that. Perhaps sitting is indeed wise.


field
ι : S.Carrier
refl : Defined S._≈_ ι

open Carrier public using (ι)

_≈_ : Rel Carrier _
_≈_ = S._≈_ on ι

-- Structure

isEquivalence : IsEquivalence _≈_
isEquivalence = record
{ refl = λ {x = x} → Carrier.refl x
; sym = S.sym
; trans = S.trans
}

-- Bundle

setoid : Setoid _ _
setoid = record { isEquivalence = isEquivalence }

-- Monomorphism

isRelHomomorphism : IsRelHomomorphism _≈_ S._≈_ ι
isRelHomomorphism = record { cong = id }

isRelMonomorphism : IsRelMonomorphism _≈_ S._≈_ ι
isRelMonomorphism = record { isHomomorphism = isRelHomomorphism ; injective = id }
20 changes: 20 additions & 0 deletions src/Relation/Binary/Construct/SubSetoid.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Conversion of a PartialSetoid into a Setoid
------------------------------------------------------------------------

open import Relation.Binary.Bundles using (PartialSetoid)

module Relation.Binary.Construct.SubSetoid
{a ℓ} (S : PartialSetoid a ℓ)
where

open import Function.Base using (id)
import Relation.Binary.Construct.Kernel as Kernel


------------------------------------------------------------------------
-- Definitions

open module SubSetoid = Kernel S id id public
5 changes: 4 additions & 1 deletion src/Relation/Binary/Definitions.agda
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ private
-- e.g. in the definition of `IsEquivalence` later in this file. This
-- convention is a legacy from the early days of the library.

Defined : Rel A ℓ → A → Set ℓ
Defined _∼_ x = x ∼ x

Reflexive : Rel A ℓ → Set _
Reflexive _∼_ = ∀ {x} → x ∼ x
Reflexive _∼_ = ∀ {x} → Defined _∼_ x

-- Generalised symmetry.

Expand Down