agda / agda-stdlib

The Agda standard library

Home Page:https://wiki.portal.chalmers.se/agda/Libraries/StandardLibrary

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[DRY] what's the best way to `public`ly re-export properties/structure?

jamesmckinna opened this issue · comments

Cf. #2255 of which this is somehow a generalisation ...

Thanks to the sophistication of the re-exporting strategies embodied in Relation.Binary.Bundles, we could streamline concrete instances of such strategies, such as in Data.List.Binary.Relation.Equality.DecSetoid.

Compare the following (23 LOC; 3 imports; 1 explicit definition; and 2 public re-exports, the first of which also introduces the correct fixity, the second shared with the existing version):

open import Relation.Binary.Bundles using (DecSetoid)

module Data.List.Relation.Binary.Equality.DecSetoid
  {a ℓ} (DS : DecSetoid a ℓ) where

import Data.List.Relation.Binary.Equality.Setoid as SetoidEquality
open import Data.List.Relation.Binary.Pointwise using (decSetoid)

------------------------------------------------------------------------
-- Additional properties

≋-decSetoid : DecSetoid _ _
≋-decSetoid = decSetoid DS

open DecSetoid ≋-decSetoid public
  using (setoid)
  renaming (isDecEquivalence to ≋-isDecEquivalence; _≟_ to _≋?_)

------------------------------------------------------------------------
-- Make all definitions from setoid equality available

open SetoidEquality setoid public

with the existing version (31 LOC; 7 imports; 3 explicit definitions, incl. the fixity declaration; and the 1 public re-export shared with the above).

So we trade economy of expression/export for explicitness of definition... although in each case, such definitions are largely by delegation, so it's not immediately clear that there is much gain in understanding, except the documentation afforded by the types...

Which is 'better'/preferable, and which style should the library adopt from v2.* onwards?

Similarly, existing style seems to be to build up, definition-by-definition, towards eg Setoid instances, as in eg. Data.List.Binary.Relation.Equality.Setoid, rather than define the Setoid first, and then open it publicly and suitably renaming its components... as:

------------------------------------------------------------------------
-- Relational properties
------------------------------------------------------------------------

≋-setoid : Setoid _ _
≋-setoid = PW.setoid S

open Setoid ≋-setoid public
  using ()
  renaming (refl to ≋-refl; reflexive to ≋-reflexive; sym to ≋-sym; trans to ≋-trans; isEquivalence to ≋-isEquivalence)

Cf. For contrast/illustration of the status quo, my earlier comments on #2382 (and @Taneb 's recent review of #2393 ), the refinement of the above heuristic would be to emphasise *re-*export of bundles/structures...

I'm happy to move towards the style you propose above. It does seem cleaner and more scalable.

Let me understand if I've understood this right. The context here seems to be that some modules introduces fundamental functionality (sometimes highly parametrized), while other modules are 'actually' creating a particular view of that functionality which is better-suited for working on particular tasks (by specializing to certain parameters, but also tailoring the exports in certain ways).

If that's an adequate description, then indeed this feels like a deeply pragmatic design approach. [It has the drawback that working simultaneously with the general version and the specific version can cause clashes -- but I would say that that is rare, will only be done by experts, and they ought to use qualified imports when doing that.]

In other words, I too agree. (But I have started to think more deeply about that 'design' paper, even though we should knock off the JOSS one first!)

@JacquesCarette I think your understanding is correct (but in rather different terms than I might either have first thought of this, or expressed it... ;-)).

My concerns, such as they are, are two-fold:

  • conceptual: trying to understand how we approach 'inheritance' in the Algebra.Bundles and Relation.*.Bundles hierarchies... in the proposed new style, putting the public export of the Setoid properties after that of DecSetoid ensures that 'super' (as it were) on properties refers consistently to the correct 'super' sub-bundle of decSetoid, rather than some accidentally extensionally equivalent, moreover explicitly defined, collection of fields with the correct types;
  • practical: DRY, reducing LOC, etc. (which also is intimately concerned with avoiding 'accidental' engineering coincidences...)