-
Notifications
You must be signed in to change notification settings - Fork 260
[ draft ] Alternative design for sub- and quotient- (Abelian)Groups
#2859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
| { isMonoid = record | ||
| { isSemigroup = record | ||
| { isMagma = record | ||
| { isEquivalence = record |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is just an experiment, but I'd certainly wish that this IsEquivalence record was pulled out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing that impressed me about @Taneb 's code was the extent to which, in various places, it manages to produces huge nested record blocks which nevertheless 'do the right thing'.
I've flip-flopped over the years between this style, and a much more incremental, define every sub-record at top-level, put the pieces together step-by-step style, which the library has to date favoured.
One reason (perhaps two or more!) I am now turning towards the 'one big record' style arises from #2391 :
- a single large object, suitably re-opened as
public, (re-)introduces all the 'correct' substructure, moreover with the 'rectified'/'official' names, rather than trying to invent proxy names for the top-level substructure in the other style - when any client imports the new constructions, they aren't faced with a (DRY) choice between cherry-picking the ad-hoc names (which may be the 'correct' ones), or facing a clash/choicepoint between such names and those names introduced by
openof substructures
In this instance (as perhaps elsewhere...) the definition of distinct isEquivalence : IsEquivalence ... fields at top-level is starting to emerge as an anti-pattern for me: once an Algebra.Structures.IsX object is in scope, or has been defined, then isEquivalence is available as a canonical projection from that, and indeed that should be the preferred mode-of-access (via open if necessary) for a substructure which exists solely
- to export canonical names
refl,sym,transfor the properties, and their derived forms - to construct
Setoids from whichRelation.Binary.Reasoning.Setoidsyntax may then be brought into scope - ...
... much of which functionality/behaviour can be achieved at a higher-level of the nesting hierarchy by suitable re-organisation of the Algebra.Properties.X hierarchy #2804 #2858 etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defining every sub-record independently also gets out of hand. I've settled on an approach more 'in the middle' where some particularly re-usable records are given top-level names.
The big record always exists, so users can choose that one if that's what they want, or the big one and open it.
I guess I was thinking of the "developer API" here rather than the "user API". So I think that's where our difference of opinion comes from, we had different modes of use in mind.
This is where natural language and Agda are insufficiently precise.
| record IsNormal {c′ ℓ′} (subgroup : Subgroup c′ ℓ′) : Set (c ⊔ ℓ ⊔ c′) where | ||
| open Subgroup subgroup using (ι) | ||
| field | ||
| conjugate : ∀ n g → _ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That _ is perverse. Sure, it can be reconstructed -- so what? Record declarations serve as documentation too!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for "perverse"... ;-)
I surely agree that
recorddeclarations should be self-documenting
but, here, I think that- an-line comment would here do as much work in explaining why a name isn't necessary...
- ... rather than, as now, having to introduce a private manifest field defining a
module(or else expose a new name for a subfield of thesubgroupobject), solely for the sake of projecting out the name of itsCarrier.
So... at rock-bottom, I chose this design as a optimisation for space (as well as that of my cognitive load, but it seems YMMV) and like all such, doing this prematurely might be harmful.
But as with the comment above about isEquivalence, I am starting to find that when we create/open substructures of this sort, it is usually in a context in which the 'missing'/'hidden' name of the type is already in scope with another pre-existing name which is more salient in that deployment context.
So the private module name, and or that of its sub-fields, is being created solely for the purpose of documentation.
Accordingly, in this setting, I made a design choice to avoid committing to creating such an 'ephemeral' name. But an inline comment should, I think, solve this problem?
I'd still be OK if you disagreed with my above thought process (which should, in any case, be documented towards any eventual codification of a library-design philosophy ;-)), and I guess part of the point of offering an 'alternative' design for these fundamantal structures was to create an opportunity for debate around such questions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would be sufficiently placated with an inline comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up just being explicit, and saving the indirection... ;-)
| open AbelianGroup abelianGroup public | ||
|
|
||
| isNormal : IsNormal subgroup | ||
| isNormal = record { normal = λ n → G.comm (ι n) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eta contract?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! In that, it is itself an eta-contraction of the original
isNormal = record { normal = λ n g → G.comm (ι n) g }Is it harmful to have done this?
Or are you asking whether the definition could be contracted further? Perhaps, but only via one of those odd Function.Base composition operators which compose only in one argument position of an n+2-ary function, which I find obscure rather than illuminate (my point-free fu is not always as strong as it might be).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I had not noticed that this had been contracted once already! I was thinking that this would be a straightforward composition. Hmm, now I wonder if the eta expanded version isn't easier to understand!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be: but work on #2863 suggests that this, plus commutativity in the Centre constructions, might better be plumbed in by other means. Further experimentation required!
|
I'm sure this alternative design makes a lot of sense to you @jamesmckinna and to @Taneb , but since I don't have the original in mind, your description relative to it does not really inform me in any substantial way of the pros and cons of each. i.e. could the PR description be made less relative to knowing the original, but rather have more information about both designs in the description please? |
|
I think that the best answer to the above comment might be to give a more detailed commentary in the source? (See ongoing/recent commits) I think that this is probably more portable/surveyable than a complex interweaving of the GitHub comment trail? This still seems to be a major bugbear in using git to debate alternatives, and to document discussion around such things, as we have observed in the past, elsewhere in this project. |
| -- which is already inherited (by definitional equality!) from the type of | ||
| -- the `⟦_⟧` parameter to `IsXHomomorphism`... | ||
|
|
||
| ι : _ → G.Carrier -- where _ = RawGroup.Carrier domain |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A last thought on this (or two, depending on how you count; maybe it's 3/2 of a thought): either of the following would also typecheck:
| ι : _ → G.Carrier -- where _ = RawGroup.Carrier domain | |
| ι : _ → _ |
or
| ι : _ → G.Carrier -- where _ = RawGroup.Carrier domain | |
| ι : _ -- where _ = RawGroup.Carrier domain → G.Carrier |
JacquesCarette
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do really like the extensive documentation.
I think some modules are in the 'wrong' place (see detailed comments).
| -- companion `Construct` sub-hierarchy (intersections etc.) below | ||
| -- `Algebra/Construct/Sub/Group/Normal` as a sub-directory. | ||
|
|
||
| module Algebra.Construct.Sub.Group.Normal {c ℓ} (G : Group c ℓ) where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why is this under Construct? This defines what being a Normal Subgroup is -- it does not construct anything!
Algebra.Gropu.Sub.Normal ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it's under Sub.Group... so if that moves, so too will/should this.
| -- to a level one *below* that of `Algebra.Construct.Sub.Ring`, | ||
| -- notwithstanding that we have yet to define `Sub.XRing`s... | ||
|
|
||
| module Algebra.Construct.Sub.Ring.Ideal {c ℓ} (R : Ring c ℓ) where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about this file not containing a construction but rather a definition. And it isn't Sub either: an Ideal is defined as a property of a Ring R. This happens to use a Sub-bimodule as part of its definition, sure, but it is not a Subring. So I think both Construct and Sub don't belong in the name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wondered about this.
Do we regard NormalSubgroup, Ideal etc. as 'special' kinds of Subobject?
Or is the specialness that hey give rise to Quotients?
I'd previously suggested to @Taneb a Quotientable hierarchy, and then Quotient.X takes an X and a Quotientable.X as parameters... but got pushback on that idea.
#2854 and #2855 put these things at the top of Algebra, and that doesn't seem right to me either.
|
|
||
| open import Algebra.Bundles using (AbelianGroup) | ||
|
|
||
| module Algebra.Construct.Sub.AbelianGroup {c ℓ} (G : AbelianGroup c ℓ) where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is better named: it does construct an AbelianGroup out of a (normal) subgroup. This seems like it is in the right place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes (but still: sigh).
|
|
||
| open import Algebra.Bundles using (Group; RawGroup) | ||
|
|
||
| module Algebra.Construct.Sub.Group {c ℓ} (G : Group c ℓ) where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again: this does not Construct anything, it gives a definition. So Sub fits, Construct does not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inherited from #2852 so we've got some retrofitting to do...
|
@JacquesCarette regarding the
I guess I took at face value that we 'construct' a subgroup by supplying a monomorphism... but I see your point. It's (potentially) a lot more complicated to do so, so we perhaps need to discuss further with @Taneb on a fresh issue/PR? |
Alternative to #2852 and #2854 , based on @Taneb's original design, but:
Normalis now belowAlgebra.Construct.Sub.GroupAlgebra.Construct.Sub.AbelianGroups added, and are automaticallyNormalHence:
Algebra.Module.Construct.Sub.Bimodules are automatically suitable asIdealsAlgebra.Construct.Sub.RingAlgebra.Construct.Quotient.RingThe high-level differences between the two approaches mostly consist in:
publicly re-export properties/structure? #2391 , in terms of making large single definitions of nestedrecords, andopening them to expose substructureAlgebrahierarchy, and their mutual dependency (aiming to flatten/linearise the latter, and making the former follow a more conventional inheritance based directory/sub-directory tree structureRing) which are based on an underlying (additive) Abelian group structure, which slightly alters the conceptual, as well as concrete dependency graph compared to Taneb's Add subgroups and submodules #2852 Normal subgroups and quotient groups #2854 and Add ideals and quotient rings #2855