Author: Jonathan D.A. Jewell j.d.a.jewell@open.ac.uk Date: 2026-02-01
aggregate-library = (common elements of phronesis stdlib ∩ Rust stdlib ∩ Haskell stdlib)
∪ (compiler utilities)
Translation: Find what’s common across ALL THREE language stlibs, extract it to aggregate-library choosing the BEST implementation for each, and each language keeps its specialized parts.
This creates a leaner library with no duplication - a single source of truth for universal patterns.
Look for operations that exist across all three language stlibs: - Phronesis (Elixir stdlib) - Rust stdlib - Haskell stdlib (Prelude, Data.*)
For each common pattern, select the implementation with the best characteristics:
| Pattern | Best From | Why |
|---|---|---|
Result/Option types |
Elixir |
Cleanest API (\{:ok, value} | \{:error, reason}) |
Collections |
Haskell |
Most elegant, composable (map, filter, fold) |
Strings |
Elixir |
Best Unicode handling |
File I/O |
Elixir |
Built-in Result handling |
Time/Duration |
Rust |
Best precision, no allocations |
Create modules in aggregate-library with the chosen implementations: -
AggregateLibrary.Result - Elixir-style -
AggregateLibrary.Collections - Haskell-style -
AggregateLibrary.FileIO - Elixir-style - AggregateLibrary.Stream
- Cross-language patterns - AggregateLibrary.Time - Rust-style
What stays in language-specific stlibs:
Phronesis (lib/phronesis/stdlib/): - Std.Consensus - Raft
consensus, distributed voting (policy-specific) - Std.BGP - AS path
analysis, route validation (network-specific) - Std.RPKI - ROA
validation (network-specific) - Std.Temporal - Policy-specific time
logic (is_expired, within_window)
Rust stdlib: - Ownership/borrowing utilities (Arc, Mutex, unsafe) - Low-level I/O (Read, Write traits) - Platform-specific APIs (Windows/Linux/macOS)
Haskell stdlib: - Type-level programming (DataKinds, GADTs) - Monad transformers (StateT, ReaderT) - Lazy evaluation primitives (seq, deepseq)
Phronesis.Stdlib.Temporal:
def now(), do: DateTime.utc_now()
def duration(seconds), do: %{seconds: seconds}
def is_expired(timestamp, duration) # policy-specific
def within_window(start, end) # policy-specificRust std::time:
Duration::from_secs(60)
Instant::now()
instant.elapsed()Haskell Data.Time:
getCurrentTime :: IO UTCTime
addUTCTime :: NominalDiffTime -> UTCTime -> UTCTimeAggregateLibrary.Time (universal):
def now() - Current timestamp
def duration(seconds) - Create duration
def add(time, duration) - Time arithmetic
def elapsed(start, end) - Calculate difference
def parse(string) - ISO8601 parsing
def format(datetime) - ISO8601 formatting
def to_unix(datetime) - Unix timestamp conversionPhronesis.Stdlib.Temporal (policy-specific only):
def is_expired(timestamp, duration) - Policy expiration check
def within_window(start, end) - Policy time window checkResult: - ✅ ONE best implementation of time ops in aggregate-library - ✅ Phronesis uses aggregate-library for basic time ops - ✅ Phronesis keeps only policy-specific time logic - ✅ Less code, better quality, single source of truth
aggregate-library/ ├── lib/aggregate_library/ │ ├── result.ex # Elixir-style Result/Option │ ├── collections.ex # Haskell-style map/filter/fold │ ├── file_io.ex # Elixir-style file ops │ ├── stream.ex # Cross-language lazy iteration │ ├── time.ex # Rust-style precision time ops │ │ │ └── a_lib/ # Compiler utilities (language-agnostic) │ ├── token.ex # Generic token structure │ ├── position.ex # Source location tracking │ ├── error.ex # Error representation │ ├── string_utils.ex # Levenshtein, indent, wrap │ ├── color_output.ex # ANSI colors │ └── ast/ │ └── traversal.ex # AST tree walking │ ├── mix.exs # Elixir project config └── COMPOSITION-GUIDE.md # This file
Phronesis used its own internal utilities:
# phronesis/lib/phronesis/lexer.ex
result = Phronesis.Internal.token_result(...)-
No Duplication: Only ONE implementation of string split, file read, time operations
-
Best Quality: Each function uses the best implementation from any of the three languages
-
Single Source of Truth: Fix a bug once, benefits all languages
-
Leaner Codebase: Phronesis stdlib shrinks (remove universal parts, keep domain-specific)
-
Clear Boundaries: Universal (aggregate-library) vs. domain (language stdlib)
✅ Add if: - Pattern exists in ALL THREE language stlibs (Phronesis, Rust, Haskell) - Implementation is truly language-agnostic - You can identify which implementation is “best”
❌ Do NOT add if: - Pattern exists in only one or two languages - Logic is domain-specific (policies, networking, consensus) - Language-specific features (ownership, monads, macros)
If aggregate-library abstraction feels forced or doesn’t work well:
-
Revert changes
-
Use language stdlib directly
-
Document why abstraction wasn’t suitable
The goal is to reduce duplication, not force abstractions that don’t fit.
When you want to extend aggregate-library to other languages (Solo, Duet, Ensemble, etc.):
-
Analyze their stlibs for common patterns
-
Compare with existing aggregate-library modules
-
Extract common parts if they exist
-
Choose best implementation (might be from new language)
-
Update aggregate-library with enhanced version
Rule: Only add patterns that are genuinely universal. Don’t force it.
✅ Phronesis stdlib is leaner (domain-specific only) ✅ aggregate-library has universal patterns (best-of-breed) ✅ No duplication across language stlibs ✅ Clear separation of concerns ✅ Easy to understand where code belongs
| Module | Source | Purpose |
|---|---|---|
Result |
Elixir |
Error handling |
Collections |
Haskell |
Map/filter/reduce |
FileIO |
Elixir |
File operations |
Stream |
Cross-language |
Lazy iteration |
Time |
Rust |
Time/duration |
ALib.Token |
Custom |
Compiler tokens |
ALib.Position |
Custom |
Source locations |
ALib.Error |
Custom |
Error messages |
ALib.StringUtils |
Custom |
String algorithms |
ALib.ColorOutput |
Custom |
Terminal colors |
ALib.AST.Traversal |
Custom |
AST walking |
aggregate-library is NOT a monolithic standard library replacement. It’s a carefully curated set of universal patterns extracted from the intersection of three mature language stlibs, choosing the best implementation for each.
Each language keeps its unique strengths in its own stdlib. aggregate-library just provides a common foundation to avoid reinventing the wheel.