RFD-0009 — Generics are functor modules and generic computations, not parametric concepts
Question
Argon needs a way to abstract over types — re-use the same modeling pattern for Lease and Loan and RentalAgreement without copy-pasting. Should the language admit parametric concepts (concept Container<T>), or restrict generics to module-level functor abstractions and per-compute generics?
Decision
Generics are admitted at two levels:
-
Functor modules — a module parameterized by other modules. Instantiation produces a fresh module with the parameter bound. Used for “this whole package shape, but with
Leasesubstituted forLoan.” -
Generic computations — a
computeparameterized by type variables. Used for “this calculation works on any concept that has these properties.”
Generics are not admitted at the concept level. There is no concept Container<T> in Argon. A concept that needs polymorphic behavior models that behavior through relations or through a functor module instance.
Rationale
Parametric concepts collide with the foundational-ontology model. A concept Container<T> introduces a class of types with no canonical instantiation in the foundational ontology. Is Container<Person> a kind? A subkind? Does it provide identity? The answer depends on how UFO (or whichever foundational ontology) handles parametric type families, and the answer differs across foundational ontologies. Building parametric concepts into the language would have leaked foundational-ontology assumptions into the compiler (RFD-0002).
Functor modules are the right granularity. The unit of reuse in real ontology engineering is rarely “one polymorphic concept.” It’s “one whole modeling pattern — these concepts, these relations, these constraints — instantiated for a specific domain.” Functor modules express that directly. The result is more than one concept, but the parameterization is at the module boundary, not the concept boundary, so the foundational-ontology layer stays clean.
Generic computations are uncontroversial. A compute function over “anything with a value: Money property” is a Hindley-Milner-style type variable that ranges over concepts satisfying a structural constraint. No foundational-ontology coupling.
Consequences
- Concept declarations do not accept type parameters in their syntactic surface.
- Module declarations admit a parameter list:
mod functor(M: SomeSignature) { … }(concrete syntax to be specified during implementation). - Compute declarations admit type variables in their parameter and return types:
compute f<T: HasValue>(x: T) -> Money. - Patterns (RFD-0019) provide the lighter-weight reuse mechanism for shapes that don’t need full module-level abstraction.