Skip to content

Conversation

jamesmckinna
Copy link
Contributor

@jamesmckinna jamesmckinna commented Aug 24, 2025

This tackles one version of how to develop 'subsetoid's via PERs. Cf. #2814

Not necessarily the 'right' way to go, but still functionality which may be useful in the future

UPDATED: to live under Relation.Binary.Construct

@jamesmckinna jamesmckinna added the subsets relies on/infleunced by/influences, various approaches to the notion of 'subset(oid)' in type theory label Aug 24, 2025
Copy link
Contributor

@JacquesCarette JacquesCarette left a comment

Choose a reason for hiding this comment

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

One quibble, but otherwise I like this now.

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

open import Data.Product.Base using (_,_; Σ; proj₁; proj₂)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know if it would be worse, or better, to have something like

Suggested change
open import Data.Product.Base using (_,_; Σ; proj₁; proj₂)
open import Data.Product.Base using (_,_; Σ)
renaming (proj₁ to ι; proj₂ to x≈x)

so that subsequent definitions can exploit such 'abstract' vocabulary/notation, rather than expose the concrete projection names?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or perhaps better still, remove/inline refl as below, and make

ι : Carrier  S.Carrier
ι = proj₁

so that it may subsequently be exported/exportable as such?

Copy link
Contributor

Choose a reason for hiding this comment

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

If you're going to go that route (second suggestion), why not bite the bullet and make the thing a record? Post-facto adding aliases for projections is what agda-unimath does... and it eventually leads to unreadable goals.

I like the first suggestion even less.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, in a way, the record-based version is (arguably) cleaner:

record SubSetoid : Set (a ⊔ ℓ) where

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

open SubSetoid public using (ι)

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

-- Structure

isEquivalence : IsEquivalence _≈_
isEquivalence = record
  { refl = λ {x = x}  SubSetoid.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 }

Copy link
Contributor

Choose a reason for hiding this comment

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

I certainly would argue so!

Copy link
Contributor Author

@jamesmckinna jamesmckinna Aug 31, 2025

Choose a reason for hiding this comment

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

In the interests of clarity: are you saying that you would prefer that it be changed in favour of the record version?

More than happy to do so if so!

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. I've retained Carrier as the name of the underlying type, but I suppose something else, such as SubSetoid, would work as well. Field name refl is kept hidden, so that its 'rectification' (wrt implicit quantification) as Setoid.refl is the way to access it.

------------------------------------------------------------------------
-- 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.

@jamesmckinna
Copy link
Contributor Author

UPDATED:

  • converted to DRAFT
  • added Relation.Binary.Construct.Kernel and Relation.Binary.Construct.SubSetoid for consideration

We can discuss where this might go, if and when, ... later.

@jamesmckinna jamesmckinna marked this pull request as draft September 3, 2025 08:44
------------------------------------------------------------------------
-- 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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition subsets relies on/infleunced by/influences, various approaches to the notion of 'subset(oid)' in type theory
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants