|
Dedekind 0.0.0
A structuralist C++23 Module Library
|
Initial F-algebras and terminal F-coalgebras. More...
#include <concepts>#include <cstddef>#include <functional>#include <tuple>#include <type_traits>#include <utility>import dedekind.category:morphism;
Classes | |
| struct | dedekind::category::detail_f_algebra::component_orders< Op > |
The component orders of a product order, where Op is one. More... | |
| struct | dedekind::category::detail_f_algebra::component_orders< ProductLeq< LA, LB > > |
| struct | dedekind::category::BetaReduction |
The β-reduction algebra: a leaf is its own normal form; a node is reduce_β over its reduced legs. reduce_β is a dependent call resolved by ADL against the node type, so a law lives next to its node: the composition unit law above is the canonical exhibit, and further node laws add their own overloads beside their vocabulary. No node carries an is-this-kind tag; dispatch is on the node type. More... | |
| struct | dedekind::category::LawAlgebra< Op > |
The law algebra: a leaf is its declared profile, a node the law engine on its legs' profiles (:posetal, arrow_node); any other node certifies nothing (sound). The second algebra for the same cata: BetaReduction lands in a normal form (a free algebra, so it decides equality), LawAlgebra in a finite domain of profiles (an abstract interpretation, so it certifies, sound, not complete). More... | |
Namespaces | |
| namespace | dedekind::category |
Concepts | |
| concept | dedekind::category::IsInitialFAlgebra |
Carrier A is the initial F-algebra for endofunctor F with structure map α. | |
| concept | dedekind::category::IsTerminalFCoalgebra |
Carrier A is the terminal F-coalgebra for endofunctor F with structure map α. | |
| concept | dedekind::category::IsTermNode |
| A node of the term functor: a type that exposes its legs. | |
| concept | dedekind::category::Steers |
An algebra that steers the fold at T (Mendler style): it recurses into the legs it chooses by cata itself, instead of the strict fold. | |
| concept | dedekind::category::detail_f_algebra::HasComponentOrders |
Op is a product order with component orders to descend into. | |
Functions | |
| template<IsArrow F, IsArrow G> | |
| constexpr auto | dedekind::category::legs (const Compose< F, G > &c) |
| The legs of a composite: the arrows it composes. | |
| template<typename β, typename T> requires Steers<β, T> || IsTermNode<T> || std::invocable<const β&, const T&> | |
| constexpr auto | dedekind::category::cata (const β &alg, const T &t) |
cata ⦇β⦈ — the catamorphism (fold): the unique F-algebra homomorphism from the initial algebra (the term itself, μF) into an algebra (B, β). | |
|
template<typename β, typename T, std::size_t... I> requires IsTermNode<T> && std::invocable< const β&, const T&, decltype(cata(std::declval<const β&>(), std::get<I>(legs(std::declval<const T&>()))))...> | |
| constexpr auto | dedekind::category::detail_f_algebra::fold_legs (const β &alg, const T &t, std::index_sequence< I... >) |
| template<IsArrow T> | |
| constexpr auto | dedekind::category::cata (const T &t) |
cata(t): the term rewritten to its normal form under the β-reduction algebra. simplify is cata. The IsArrow gate keeps a bare product out of the term universe. | |
reduce_β for a Compose node — the canonical β exhibit | |
Dispatch is structural on | |
| template<IsArrow F, IsArrow G, IsArrow RF, IsArrow RG> | |
| constexpr auto | dedekind::category::reduce_β (const Compose< F, G > &, const RF &rf, const RG &rg) |
| template<IsArrow F, IsArrow G, typename T, IsArrow RG> | |
| constexpr RG | dedekind::category::reduce_β (const Compose< F, G > &, const Identity< T > &, const RG &rg) |
| template<IsArrow F, IsArrow G, IsArrow RF, typename T> | |
| constexpr RF | dedekind::category::reduce_β (const Compose< F, G > &, const RF &rf, const Identity< T > &) |
| template<IsArrow F, IsArrow G, typename T, typename U> | |
| constexpr Identity< T > | dedekind::category::reduce_β (const Compose< F, G > &, const Identity< T > &i, const Identity< U > &) |
| template<typename F, typename G, typename RF, typename RG> | |
| constexpr auto | dedekind::category::reduce_β (const Pairing< F, G > &, const RF &rf, const RG &rg) |
| A pairing (copairing) rebuilt from its reduced legs: inert. | |
| template<typename F, typename G, typename RF, typename RG> | |
| constexpr auto | dedekind::category::reduce_β (const Copairing< F, G > &, const RF &rf, const RG &rg) |
Variables | |
| template<typename F, typename A, typename α> | |
| constexpr bool | dedekind::category::is_initial_f_algebra_v = false |
Opt-in trait: does carrier A witness the initial F-algebra universal property for endofunctor F with structure map α? | |
| template<typename F, typename A, typename α> | |
| constexpr bool | dedekind::category::is_terminal_f_coalgebra_v = false |
Opt-in trait: does carrier A witness the terminal F-coalgebra universal property for endofunctor F with structure map α? | |
Initial F-algebras and terminal F-coalgebras.
@partition :f_algebra
Pierce §5 introduces F-algebras and F-coalgebras immediately after functors and before natural transformations because they are the load-bearing concept that grounds recursive types and the universal property of recursion. This project's :functor partition already carries the structural-shape concepts:
IsFAlgebra<Carrier, Structure, Functor> — structure map F → A.
IsFCoalgebra<Carrier, Structure, Functor> — structure map A → F .
What was missing — and what this partition adds — is the universal-property layer:
Initial F-algebra: an F-algebra (A, α) is initial if for every other F-algebra (B, β) there exists a unique morphism h : A → B with h ∘ α = β ∘ F(h). That unique morphism is the catamorphism (fold).
Terminal F-coalgebra: dually; the unique morphism is the anamorphism (unfold).
The Jlt posture is data only: initial algebras in Set, codata out of scope as values (the Jlt paper's Rule 3). The restriction lives in the posture (the rules, jlt-lint, the listings), not here: this partition keeps both halves of the dual, IsInitialFAlgebra and IsTerminalFCoalgebra, so that codata (Trsk, later) is registered beside the data side and needs no rewrite of it. Jlt's recursion pair stays on the initial algebra: cata out of \(\mu F\), and unfold of Lambek's inverse \(\mathit{prior} = \mathit{in}^{-1}\) on \(\mu F\) itself (:chain), which always ends; an anamorphism into \(\nu F\) is a different arrow and keeps a different name.
The :nno partition reifies Lawvere's NNO universal property as the (z, s) shape — pedagogically the more recognisable form for a working mathematician. The textbook reading of NNO is that it is the initial F-algebra for F(X) = 1 + X (the "Maybe" endofunctor; Pierce §5.4, Mac Lane III–VI). This partition exposes that reading as a separate concept; the two universal properties are operationally equivalent — the (z, s) pair induces the structure map [z, s] : 1 + N → N via coproduct copairing on the standard injections inl : 1 → 1 + N and inr : N → 1 + N.
The 1 in 1 + N is the terminal object of the ambient category — concretely, the category::One = std::monostate reified in the :limit partition (which carries IsTerminalObject<One> as a static_assert). The categorical pattern IsInitialFAlgebra is itself one level up from the IsInitialObject reification in :limit (which pins category::Zero = std::nullptr_t as the initial in Set): the F-Alg category has its own initial object (μF, in), and IsInitialFAlgebra is the engineer's honesty obligation that a particular (A, α) is that initial object. See f_algebra_test.cpp for the static_assert witnesses linking the two layers.
As with :nno, C++ concepts cannot quantify over the universal property's uniqueness clause. The structural shape ( IsFAlgebra / IsFCoalgebra in :functor) is what the type system can pin; the universal-property concepts here are opt-in traits that carriers must explicitly register via is_initial_f_algebra_v / is_terminal_f_coalgebra_v. The trait is the engineer's honesty obligation: declaring it asserts that the carrier truly satisfies the universal property, and the paper's ethical register applies (Wadler 2015, NSPE Code of Ethics). An identical opt-in pattern is used by algebra:initial_ring (PR #451) for ℤ as the initial ring.
The dual pair carries the recursion ↔ corecursion split structurally — no catamorphism without an anamorphism. Both halves land in this partition as concepts; the operational discharge of the fold is cata below ( ana / hylo are still to come).
dedekind.algebra:universal (IsAlgebra<T, Ops...>) for the universal-algebra (A, F) reading of the same notion. Per the textbook isomorphism Alg(Σ) ≅ F_Σ-Alg (Pierce §2.2), every IsAlgebra<T, Ops...> there corresponds to an F-algebra here for the polynomial endofunctor F_Σ generated by the signature Σ = (Ops...). The two partitions name the same structural fragment from the universal-algebra and category-theoretic traditions respectively.