Hierarchy Builder: algebraic hierarchies made easy in Coq with Elpi

It is nowadays customary to organize libraries of machine checked proofs around hierarchies of algebraic structures [2, 6, 8, 16, 18, 23, 27]. One inﬂuential example is the Mathematical Components library on top of which the long and intricate proof of the Odd Order Theorem could be fully formalized [14]. Still, building algebraic hierarchies in a proof assistant such as Coq [9] requires a lot of manual labor and often a deep expertise in the internals of the prover [13, 17]. Moreover, according to our experience [26], making a hierarchy evolve without causing breakage in client code is equally tricky: even a simple refactoring such as splitting a structure into two simpler ones is hard to get right. In this paper we describe HB , a high level language to build hierarchies of algebraic structures and to make these hierarchies evolve without breaking user code. The key concepts are the ones of factory , builder and abbreviation that let the hierarchy developer describe an actual interface for their library. Behind that interface the developer can provide appropriate code to ensure backward compatibility. We implement the HB language in the hierarchy-builder addon for the Coq system using the Elpi [11, 28] extension language.


Introduction
Modern libraries of machine checked proofs are organized around hierarchies of algebraic structures [2,6,8,16,18,23,27].For example the Mathematical Components library for the Coq system [9] provides a very rich, ever growing, hierarchy of structures such as group, ring, module, algebra, field, partial order, order, lattice. . .The hierarchy does not only serve the purpose of organizing knowledge, but also to make it easy to exploit it.Indeed the interactive prover can take advantage of the structure of the library and the relation between its concepts to infer part of information usually left implicit by the user, a capability that turned out to be key to tame the complexity and size of the formal proof of the Odd Order Theorem [14].
The hierarchy of the Mathematical Components library is implemented following the discipline of Packed Classes initially introduced by Garillot, Gonthier, Mahboubi and Rideau [13] and later also adopted by Affeldt, Nowak, and Saikawa to describe a hierarchy of monadic effects [2] and by Boldo, Lelay, and Melquiond in the Coquelicot library of real analysis [6].We call Packed Classes a discipline, and not a language, because, in spite of its many virtues, it is unwieldy to use.In particular it leaks to the user many of the technical details of the Coq system.As a result, one needs to be a Coq expert in order to build or modify a hierarchy, and even experts make mistakes as shown in [26].Another inconvenience of the Packed Classes discipline is that even simple changes to the hierarchy, such as splitting a structure into two simpler ones, break user code.
In this paper we describe HB, a high level language to build hierarchies of algebraic structures and to make these hierarchies evolve without breaking user code.The key concepts are the ones of factory, builder and abbreviation that let the hierarchy developer describe an actual interface for their library.Behind that interface the developer can provide appropriate code to ensure backward compatibility.We implement the HB language by compiling it to a variant of the Packed Classes discipline, that we call flat, in the hierarchy-builder addon for Coq.We write this addon using the Elpi [11,28] extension language.
To sum up, the main contributions of the paper are: the design of the HB language, the compilation of HB to the (flat) Packed Classes discipline, and the implementation of HB in the hierarchy-builder addon for Coq.The paper is organized as follows.Via an example we introduce HB and its key ideas.We then describe the discipline of Packed Classes and we show how HB can be compiled to it.We then discuss the implementation of the Coq addon via the Elpi extension language and we position HB in the literature.In order to build a structure we need to declare some factories and later assemble them.One kind of factory supported by HB, the simplest one, is called mixin and is embodied by a record that gathers operations and properties.
Mixins are declared via the HB.mixin command that takes a record declaration with a type parameter and a possibly empty list of factories for that type.The code between lines 1 and 7 declares a mixin that can turn a naked type M into a monoid, hence we chose the name to be Monoid_of_Type.
The HB.structure command takes in input a definition for a sigma type S that equips a type with a list of factories.It registers a structure S in the hierarchy placing any definition specific to that structure inside a Coq module named S. Line 8 hence forges the Monoid structure.
Line 10 declares a second mixin collecting the operations and properties that are needed in order to enrich a monoid to a ring, hence the name Ring_of_Monoid.Indeed this time the type variable R is followed by Monoid that enriches R with the operations and properties of monoids.As a consequence add and zero can be used to express the new properties.
The last line declares the Ring structure to hold all the axioms declared so far.We can now inspect the contents of the hierarchy and then proceed to build a theory about abstract We can print the type for monoids as forged by HB (line 1).It packs a carrier, called sort, and the collection of operation and properties that we omit for brevity.We can also look at the type of two constants synthesized by HB out of the hierarchy declaration.Remark F S C D 2 0 2 0 that while the names of the constants come from the names of mixin fields, their types differ.In particular they are quantified over a Monoid.typeor Ring.type, and not a simple type as in the mixins.Moreover we evince that the sort projection is declared as an implicit coercion [24] and is automatically inserted in order to make M -> M -> M a meaningful type for binary operations on the carrier of M. Last, we see that properties are quantified on (hence apply to) the structure they belong to but use, in their statements, operations belonging to simpler structures.For example addNr is a property of a ring but its statement mentions add, the operation of the underlying monoid.
We then follow the proof of Hankel [5] to show that ring axioms imply the commutativity of the underlying monoid (line 5).This simple example shows we can populate the theory of abstract rings with new results.
We use the Monoid_of_Type.Build abbreviation (line 8) in order to build an instance of the Monoid structure for binary integers Z.We then register that monoid instance as the canonical one on Z (line 11) via the command HB.instance.We can similarly declare that Z forms a ring by using the Ring_of_Monoid.Build abbreviation (lines 13 and 18).Note that the Ring_of_Monoid.Build abbreviation is not a plain record constructor for Ring_of_Monoid, since that would require more arguments, namely the monoid ones (see the _ at line 13).The abbreviation synthesized by HB infers them automatically (as in [17,Section 7]) thanks to the HB.instance declaration given just above.
From now on the axioms as well as the abstract theory of rings apply to integers, as shown in lemma exercise.The details of the proof do not matter here, what is worth pointing out is that in a single statement we mix monoid (e.g.+) and ring (e.g.-) operations and in the proof we use monoid axioms (e.g.addrA), ring axioms (e.g.addrN) and ring lemmas (e.g.addrC), all seamlessly.

Evolution of the hierarchy
We proceed by accommodating the intermediate structure of Abelian groups.Some operations and properties were moved from the old mixin for rings into a newborn mixin AbelianGroup_of_Monoid that gathers the axioms needed to turn a monoid into an Abelian group.Consequently the mixin for rings is now called Ring_of_AbelianGroup (instead of Ring_of_Monoid) since it expects the type R to be already an Abelian group and hence gathers fewer axioms.While operations moved from one structure to another, some properties undergo a deep change in their status.The lemma addrC part of the abstract theory of rings is now an axiom of Abelian groups, while addrN is no more an axiom of rings, but rather a theorem of the abstract theory of Abelian groups proved at line 20.
It is worth clarifying here what axioms and lemmas are by looking at the two distinct use cases for a hierarchy: 1) develop the abstract theory of some structure; 2) apply the abstract theory on some concrete example.In the first case all the axioms of the structure are (assumed to be) theorems so the distinction between axiom and theorem does not matter.This is what happens in the proof of addNr by taking R to be of type AbelianGroup.typeas an assumption.In the second case, in order to show Coq that a data type and some operations forms a structure, one must pick the axioms of the structure an prove them for that specific type and operations.For example the Ring_of_Monoid.Build abbreviation is used at page 3 to package the set of proofs that make Z a ring (proviso Z is already a monoid).
With this new version of the hierarchy, that we name V2, the axiomatic that was previously exposed to user changed, and indeed code written for version V1 breaks.For example the declaration of the canonical ring over the integers fails, if only because we do not have a Ring_of_Monoid.Build abbreviation anymore.
Our objective is to obtain a version of the hierarchy, that we name V3, that does not only feature Abelian groups but that is also backward compatible with V1.

The missing puzzle piece
Figure 1 The evolution of the hierarchy.V3 is backward compatible with V1, while V2 is not.
The key to make a hierarchy evolve without breaking user code is the full fledged notion of factory (the mixins seen so far are degenerate, trivial, factories).Factories, like mixins, are packages for operations and properties but are not directly used in the definition of structures.Instead a factory is equipped with builders: user provided pieces of code that extract from the factory the contents of mixins, so that existing abbreviations can be used.
As depicted in Figure 1 we change again the hierarchy by declaring a Ring_of_Monoid factory, that, from the user point of view, will look indistinguishable from the old Ring_of_Monoid mixin and hence grant backward compatibility between version V3 and version V1.The record Ring_of_Monoid is the same we declared as a mixin in version V1.In order to make a factory out of it we equip it with two definitions that embody the builders.The first is to_AbelianGroup_of_Monoid and explains how to build an AbelianGroup structure out of the factory axioms (named f, line 3).This construction is also registered as canonical for R, so that the next construction to_Ring_of_AbelianGroup can call the Ring_of_AbelianGroup.Build abbreviation that requires R to be an AbelianGroup.It is worth pointing out that the proof of addrC we had in V1 is now required in order to write the builder for Abelian groups, while the addrN field is not used (the same statement is already part of the theory of Abelian groups, see line 20 of the previous code snippet).
Thanks to this factory we can now declare Z to be an instance of a ring using the Ring_of_Monoid.Build abbreviation.The associated builders generate, behind the scenes, instances of the Ring_of_AbelianGroup and AbelianGroup_of_Monoid mixins that in turn are used to build instances of the AbelianGroup and Ring structures.Indeed, when used in the context of the hierarchy version V3, the command HB.instance Z Z_Ring_axioms makes Z an instance of both structures, and not just the Ring one as in version V1.Thanks to that the proof of example can use the theory of both structures, for example addrC holds on Abelian groups, addrA holds on monoids, while addr1 holds on rings.As a result the very same proof works on both version V1 and V3.
Last, it is worth pointing out that the new factory makes the following two lines equivalent (the former declares rings in V1) since they both describe the same set of mixins.

HB.structure Definition
This is another example of client code that would not break: the client of the hierarchy is allowed to declare new structures on top of existing ones.

HB in a nutshell
By using HB the hierarchy designer has the following freedoms and advantages.
Operations and properties (axioms) are made available to the user as soon as they are used in a structure.The hierarchy designer is free to move them from one to another and replace an axiom by a lemma and vice versa.Structures cannot disappear but the way they are built may change.The hierarchy designer is free to split structures into smaller ones in order to better factor and reuse parts of the hierarchy and the library that follows it.Mixins cannot disappear but can change considerably in their implementation.A mixin can become a full fledged factory equipped with builders to ensure backward compatibility.
HB high level commands compile to the discipline of Packed Classes (Coq modules, records, coercions, implicit arguments, canonical structure instances, notations, abbreviations).This process lifts a considerable burden from the shoulders of the hierarchy designer and the final user who are no longer required to master the details of Packed Classes.

3
The HB language The Coq terms handled by HB are subdivided in five categories, the mixins M, the factories F, builders B, the classes C and the structures S. Mixins, factories and instances are tagged by the user, through the commands HB.mixin, HB.factory and HB.instance, and the user may rely on their implementation.However structures and classes are generated with the command HB.structure and builders are generated when using HB.instance while declaring a factory, and the user may only refer to structure types, but should never rely on their implementation, neither should they rely on explicit builders.

Mixins, factories and instances
In this section, we call "distinguished" a Coq definition or record that the developer of a library has labeled "mixin", "factory", "builder", "class" or "structure".

Definition 1 (M, mixins).
A mixin m ∈ M is a distinguished Coq record with one or more parameters.The first parameter must be a (T : Type), while the other parameters are mixins (m i ) i∈{1,...,n} , each of which is applied to T and possibly previous mixin variables.I.e.

. p σ(n,qn)
and where for all i ∈ {1, . . ., n} we have q i ∈ N and the arguments of m i ∈ M consist in q i of the previously quantified mixin parameters p k , i.e. for all k ∈ {1, . . ., q i }, we have σ(i, k) ∈ {1, . . ., i − 1}.Note that the builders of a given factory have the same set of dependencies.
Definition 10 (from).We define from(f, m n+1 ) = µ to be the (unique) builder for m n+1 from the factory f , when it exists.
Note that from is not a total function, and that from(f, m) is defined if and only if there is a declared builder that shows how to build m from f .In this case, we say f provides m.
Definition 11 (provides).provides(f ) = {m | from(f, m) is defined} ∈ ℘ (M) the set of mixins that a factory f ∈ F provides, through its builders.
Mixins are declared by the user as the fundamental building blocks of a hierarchy.As the next proposition shows they shall not be regarded as different from regular factories, since they are a special case.

Proposition 12 (M ⊆ F).
There is a way to see mixins as factories.Declares the record axioms inside a module M.This record M.axioms depends on the mixins requires(M.axioms)= dep(M.axioms)= provides ({f 1 , . . ., f n }) and is registered both as a mixin and a factory.Finally It exports an abbreviation M.Build and a notation M standing for M.axioms, so that the module name can be used to denote the axioms record it contains.

Coq command
to declare an instance: HB.instance X b 1 . . .b k , synthesizes terms corresponding to all the mixins that can be built from the b i .Indeed if b i : f i T . .., then this command creates elements of types provides ({f 1 , . . ., f k }) .This command also generates unification hints as described in Section 4. Declares the record axioms inside a module F. This record F.axioms depends on the mixins requires(F.axioms)= provides ({f 1 , . . ., f n }) and is registered as a factory.It exports an abbreviation F.Build and a notation F standing for F.axioms, so that the module name can be used to denote the axioms record it contains.Finally it uses the factory instances b n+1 , . . ., b n+k provided by the user in order to derive builders, so that provides(F) = provides ({f n+1 , . . ., f n+k }) .It is thus necessary that requires ({f n+1 , . . ., f n+k }) ⊆ provides ({f 1 , . . ., f n }) .

Coq commands
Note that the b i are not builders since their return types are not necessarily mixins, but could be factories.However, since all factories provide mixins through builders, we obtain builders out of each b i by function composition.

Classes and structures Definition 13 (C, class). A class c ∈ C is a distinguished Coq record with one parameter (T : Type). The type of each field is a mixin in M applied to T and, if needed, any number of other fields:
1 Record c (T : Type) := { p1 : m1 T ; .. ; p i : m i T p σ(i,1) . . .p σ(i,qi) ; ..}. Definition 14 (def , class definition).We call def (c) ∈ ℘ (M) the set of mixins mentioned in the fields of the class, i.e. {m 1 , . . ., m n }.Given that class records are well typed in the empty context the set of mixin records is closed transitively.The implementation enforces that no two class records contains the same set of mixins (disregarding the order of the fields), i.e. def is injective.
Programming invariant for def For all f ∈ F:

∃C ⊆ C, def (C) = requires (f ).
Classes could also be seen as factories.
Proposition 15 (C ⊆ F).For all m ∈ def (c) we have from(c, m i ) = p i , and it follows that requires(c) = ∅, provides(c) = def (c).
However since classes are generated, their implementation may change, thus users should not rely on constructors of classes.Hence the only way users may refer to a class is as an argument of HB.mixin, HB.factory or HB.structure.

Automatic inference of mixins
Since mixins may change but factories stay the same, HB commands must never rely on a particular set of mixins as arguments, and factory arguments must never be given explicitly by the user.As described in Sections 3.1 and 3.2, HB commands take a list of factories as arguments, which they expand into lists of mixins behind the scene.However factory types and constructors have mixin arguments that must be inferred automatically when used.To this end, the commands HB.mixin and HB.factory generate abbreviations for the user to replace uses of constructors of factories.These commands first create a record f aux with a constructor F aux and then create abbreviations f and F that automatically fill the mixin arguments of f aux and F aux respectively.See [17,Section 7] for a detailed description of how to implement these abbreviations in Coq.

4
The target language: Coq with Packed, flat, Classes The language of Packed Classes [13] is used directly to describe the algebraic hierarchy of the Mathematical Components library.It is based on a disciplined use of records and projections and on the possibility of extending the elaborator of Coq via the declaration of Canonical Structures [17] instances.In this section, we describe the flat variant of Packed Classes, the target language of hierarchy-builder, through the hierarchy V3 extended with semirings.
The hierarchy-builder addon can generate all the Coq declarations in this section automatically, but some details are omitted for brevity in this section.

Describing structures with records and projections
We describe mathematical structures with three kinds of dependent records: mixins, classes, and structures.As shown in Section 2, a mixin gathers operators and axioms newly introduced by a structure.As in [13, Section 2.4][26, Section 2], a class record is parametrized by the carrier type (T : Type) and gathers all the operators and axioms of a structure by assembling mixins, and a Structure type (a record) bundles a carrier and its class instance, as follows.The Monoid module plays the role of a name space and forces us to write qualified names such as Monoid.type;as a consequence we can reuse the same unqualified names for other structures, i.e., class and structure record can always be named as axioms and type respectively.

Module
Mixins and classes are internal definitions to structures; in contrast, Monoid.type is part of the interface of the monoid structure.As seen in section 2, we declare Monoid.sort as an implicit coercion and lift monoid operators and axioms from projections for the monoid mixin to definitions and lemmas for Monoid.typeas follows.In the flat variant of Packed Classes, a class record gathers mixins as its fields directly as in above.In contrast, a class record of the non-flat variant packs a class instance of one of the superclasses with remaining mixins, which reduces the amount of code to implement inheritance significantly.Since we do not need to care about the amount of code in automated generation, hierarchy-builder uses the flat variant of Packed Classes as its target language.
As in the monoid structure, we declare AbelianGroup.sortas an implicit coercion and lift additive inverse opp and Abelian group axioms.Since Abelian groups inherit from monoids, we also declare an implicit coercion from Abelian groups to monoids.A coercion between structures can be defined in two steps: first a coercion between the class record of the superclass to the class record of the subclass (line 2); and a coercion between structure records (line 4) relying on the first one.

Multiple inheritance
In order to introduce multiple inheritance, we extend the hierarchy described in Section 2.2 with the structure of semirings as depicted in Figure 2, and name it V4.Semirings introduce the binary multiplication operator mul and its identity element one.For the sake of completeness, the full code of V4 is available in Appendix C. We define implicit coercions from the semiring structure to the carrier and the monoid structure, and we lift semiring operators and axioms as follows: The class record is defined by gathering the monoid, Abelian group, and semiring mixins.Since the rings inherit from monoids, semirings, and Abelian groups, we define implicit coercions from the ring structure to those three structures.

Linking structures and instances via Canonical Structures
We recall here how to use the Canonical Structures [17,25] mechanism, which lets the user extend the elaborator of Coq, in order to handle inheritance and inference of structure [1,26,13].This software component takes as input a term as written by the user and has to infer all the missing information that is necessary in order to make the term well typed.
A first example of elaboration that requires canonical structures is 0 + 1.After removing all syntactic facilities, the underlying Coq term is (add _ (zero _)) (one _) where _ stands for an implicit piece of information to be inferred and the constants add and zero come from the monoid structure while one comes from semirings.When the term is type checked each _ is replaced by a unification variable written ?v .Respectively, the head and the argument of the top application can be typed as follows: add ?M (zero ?M) : Monoid.sort?M -> Monoid.sort?M one ?SR : SemiRing.sort?SR where ?M : Monoid.type and ?SR : SemiRing.type.In order to type check the application Coq has to unify Monoid.sort?M with SemiRing.sort?SR , which is not trivial: it amounts at finding a structure that is both a monoid and a semiring, possibly the smallest one [26,Sect. 4].This piece of information can be inferred from the hierarchy and its inheritance relation (Definition 17) and we can tell Coq to exploit it by declaring SemiRing_to_Monoid : SemiRing.type-> Monoid.type as canonical.With that hint Coq will pick ?M to be SemiRing_to_Monoid ?SR as the canonical solution for this unification problem.In general, all the coercions between structures must be declared as canonical.
Another example of elaboration problem is −1, which hides the term opp _ (one _).Here opp and one are respectively from Abelian groups and semirings, which do not inherit each other but whose smallest common substructure is rings; thus we have to extend the unifier to solve a unification problem AbelianGroup.sort?AbG = SemiRing.sort?SR by instantiating ?AbG and ?SR with Ring_to_AbelianGroup ?R and Ring_to_SemiRing ?R respectively where ?R is a fresh unification variable of type Ring.type.This hint can be given as follows: Canonical AbelianGroup_to_SemiRing (S : Ring.type) := SemiRing.Pack (AbelianGroup.sort(Ring_to_AbelianGroup S)) (Ring.classS)).
Similarly, one can apply an algebraic theory to an instance (an example) of that structure, e.g., 2 × 3 where 2 and 3 have type Z.The same mechanism of canonical structures let us extend the unifier to solve SemiRing.type?= Z.

5
The implementation of HB in Coq-Elpi The implementation is based on the Elpi extension language for Coq.In this section we introduce the features of the programming language that came in handy in the development of HB and comment a few code snippets.Coq-Elpi [28] is a Coq plugin embedding Elpi and providing an extensive, high level, API to access and script the Coq system at the vernacular level.This API lives in the coq namespace and lets one easily declare records, coercions, canonical structures, modules, implicit arguments, etc.The most basic Coq data type exposed to Elpi is the one of references to global declarations: The arguments of the three constructors are opaque to Elpi, that can only use values of these types via dedicated APIs.For example the API for declaring an inductive type will generate a value of type inductive that is printed as, for example, «nat».

F S C D 2 0 2 0
Elpi [11] is a dialect of λProlog [19], an higher order logic programming language that makes it easy to manipulate abstract syntax tree with binders.Coq-Elpi takes full advantage of this capability by representing Coq terms in Higher Order Abstract Syntax [20] style, reusing the binder of the programming language in order to represent Coq's ones.Here is an excerpt of the data type of Coq terms: Data types with binders are also used as input to high level APIs that build terms behind the scenes.For example a Coq record is just an inductive type and the API to declare one must allow the type of a field to depend on the fields that comes before it.Note that the field constructor takes a coercion flag, the name of the field, its type and binds a term in the remaining record declaration.The pred keyword documents types and modes (input or output) of the arguments of a predicate, while external signals that the predicate is a builtin (in other words it is implemented in OCaml rather than λProlog).
We comment these two builtin predicates and the indt-decl type while looking at the code of declare-structure that is in charge of scripting the following Coq code: The following Elpi code builds the declaration, type checks it, adds it to the Coq environment and finally returns the projections for the sort and the class fields.In [7] Carette and O'Connor describe the language of Theory Presentation Combinators that can be used to describe a hierarchy of algebraic structures.They focus on the categorical semantics of the language that is built upon the category of context.They do not describe any actual compilation to the language of a mainstream interactive prover, indeed they claim their language to be mostly type theory independent.We know they considered targeting type theory and the language of unification hints [4] (a superset of the one of Canonical Structures), but we could not find any written trace of that.Language-wise they provide keywords such as combine and over to share (reuse) a property when defining a new structure.For example in order to avoid restating the commutativity property when defining Abelian groups they combine a commutative monoid and a group forcing the subjacent monoid to coincide: CommutativeGroup := combine CommutativeMonoid , Group over Monoid.In our language HB the same role is played by mixins.A mixin lets one write once and for all a property and abstract it over types and operations so that it can be reused in all the structures that need it.One operation HB allows for but that does not seem to be possible in the setting of Presentation Combinators is the one of replacing an axiom with a lemma and vice versa.As shown in subsection 2.1 HB supports that.
The MMT system [22] provides a framework to describe formal languages in a logical framework, providing good support for binders and notations.It also provides an expressive module system to organize theories and express relations among them in the form of functors.At the time of writing it provides limited support for elaborating user input taking systematic advantage of the contents of the theories.The elaborator can be extended by the user writing Scala code, and in principle use the contents of the libraries to make sense of an incomplete expressions, but no higher level language or mechanism is provided.
The library of the Mizar system features a hierarchy of algebraic structures [15].In spite of lacking dependent types, Mizar provides the concept of attributed types and adjectives that can be used to describe the signature of structures as one would do with a dependently typed record and their properties as one would define a conjunctive predicate.The Mizar language also provides the notion of cluster that is used to link structures: by showing that property P implies property Q one can inform automation that structures characterized by P are instances of structures characterized by Q.The foundational theory of Mizar features an extensional notion of equality that makes it easy to share the signature or the properties of structures by just requiring a proof of their equivalence that is in turn used by automation to treat equivalent structures as equal.
The concepts of factory and builder presented here is akin to the AbstractFactory and Builder pattern from "the Gang Of Four" design patterns [12] in the sense that factories are used to build an arbitrary number of objects (here mixin instances).

Conclusion
In this paper we design and implement HB, a high level language to describe hierarchies of algebraic structures.The implementation of HB is based on the Elpi extension language for the Coq system and is available at https://github.com/math-comp/hierarchy-builder.
The implementation amounts to approximately a thousand lines of (commented) Elpi code and tree hundred lines of Coq vernacular.It took less than one month to implement HB, but its design took several years of attempts and fruitful discussions with the people we thank in the front page of this paper.The HB language is only loosely tied to Coq or even Type Theory.We believe it could be adopted with no major change to other tools.Indeed the properties and invariants that link factories, mixins and classes are key to rule out meaningless or ambiguous sentences and are not specific to our logic setting.Moreover most logics feature packing construction similar to records.
The compilation scheme we present in section 4 is tied to dependent records, that are available in Coq but also in other provers based on Type Theory such a Matita [3] and Lean [10].We chose the flat variant of Packed Classes as the target for HB because the Mathematical Components library uses Packed Classes as well: As of today Packed Classes offer the best compromise between flexibility and performance [17,Section 8] in Coq.Of course one could imagine a future were other approaches such as telescopes [21] or unbundled classes [27] would offer equal or better performances in Coq, or in another system.It is a virtue of our work to provide a user language that is separate from the implementation one.We believe it would take a minor coding effort to retarget HB to another bundling approach.
We leave to future work extending HB to support structures parametrized by structures such as the one of module over a ring.We also leave to future work the automatic synthesis of the notion of morphism between structures of the hierarchy.

Figure 2
Figure2V4 introduces multiple inheritance.For brevity we omit the factories/builders for the upper arrows.
Note that the fun constructor holds a λProlog function.In this syntax the Coq term (fun x : nat => x x) becomes (fun (global (indt «nat»)) x\ app[x, x]) where x\ binds x in the body of the function.Substitution of a bound variable for a term can be computed by applying a term (of function type) to an argument.