Back to skills
SkillHub ClubShip Full StackFull Stack
tuple-nav-composition
Imported from https://github.com/plurigrid/asi.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Stars
10
Hot score
84
Updated
March 20, 2026
Overall rating
C3.8
Composite score
3.8
Best-practice grade
B77.6
Install command
npx @skill-hub/cli install plurigrid-asi-tuple-nav-composition
Repository
plurigrid/asi
Skill path: ies/music-topos/.ruler/skills/tuple-nav-composition
Imported from https://github.com/plurigrid/asi.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack.
Target audience: everyone.
License: MIT.
Original source
Catalog source: SkillHub Club.
Repository owner: plurigrid.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install tuple-nav-composition into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/plurigrid/asi before adding tuple-nav-composition to shared team environments
- Use tuple-nav-composition for development workflows
Works across
Claude CodeCodex CLIGemini CLIOpenCode
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
--- name: tuple-nav-composition description: Tuple and product structure navigation with composition source: Category theory, product types, Cartesian logic license: MIT trit: 0 gf3_triad: "type-inference-validation (-1) ⊗ tuple-nav-composition (0) ⊗ constraint-generalization (+1)" status: Production Ready --- # Tuple Nav Composition ## Core Concept Navigation through **product structures** (tuples, named tuples, records) where multiple fields must be accessed and composed in parallel. A TupleNav is a bundled Navigator that operates on all fields of a product simultaneously, maintaining **structural integrity** through composition. ## Why Tuple Navigation? Standard Specter navigators work on **sequences** (ALL, each element). But what about simultaneous access to multiple fields? ```julia # Without TupleNav: Access fields separately, type mismatch risk person = (name="Alice", age=30, email="[email protected]") name_nav = @late_nav([INDEX(1)]) # But tuples aren't indexed this way! age_nav = @late_nav([INDEX(2)]) # Fragile, error-prone # With TupleNav: Access structurally, type-safe composition record_nav = @tuple_nav([:name, :age]) # Access both fields as unit ``` ## Architecture ### TupleNav Structure ```julia struct TupleNav fields::Vector{Symbol} # Field names to navigate navigators::Dict{Symbol, Navigator} # Navigator for each field composition_strategy::Symbol # :parallel, :sequential, :reduce output_type::Type # (Field1Type, Field2Type, ...) end ``` ### Product Types | Type | Navigation | |------|-----------| | `(T1, T2, T3)` | Positional tuple | | `NamedTuple{(:a, :b, :c)}` | Named access | | `@NamedTuple{a::T1, b::T2}` | Struct-like | | `Dict{K, V}` | Key-based dictionary | | Record/DataClass | Field-based | ### Composition Strategies **`:parallel`** - Access all fields simultaneously ```julia nav = @tuple_nav([:x, :y, :z], strategy=:parallel) result = nav_select(nav, (x=1, y=2, z=3), id) # => ((x=1), (y=2), (z=3)) # All accessed at once ``` **`:sequential`** - Access fields in order, threading results ```julia nav = @tuple_nav([:x, :y, :z], strategy=:sequential) # Field y receives result from x, z receives from y, etc. ``` **`:reduce`** - Fold/reduce across fields ```julia nav = @tuple_nav([:x, :y, :z], strategy=:reduce) # Combine results across fields: x + y + z ``` ## API ### TupleNav Creation **`@tuple_nav(fields, strategy=:parallel)`** Creates a TupleNav for navigating product types. ```julia # Access name and email from person record nav = @tuple_nav([:name, :email]) person = (name="Alice", email="[email protected]", age=30) result = nav_select(nav, person, identity) # => (name="Alice", email="[email protected]") ``` **`tuple_nav(fields::Vector{Symbol}, structure_type::Type)`** Explicitly typed TupleNav. ```julia PersonType = NamedTuple{(:name, :age, :email)} nav = tuple_nav([:name, :email], PersonType) # Type-checked at compile time ``` ### Composition **`compose_tuple_navs(nav1::TupleNav, nav2::TupleNav) :: TupleNav`** Combines two product navigators. ```julia nav_identity = @tuple_nav([:id, :name]) # Extract identity nav_contact = @tuple_nav([:email, :phone]) # Extract contact nav_combined = compose_tuple_navs(nav_identity, nav_contact) # Result has all 4 fields: id, name, email, phone ``` ### Nested Products **`nested_tuple_nav(path::Vector, fields::Vector{Symbol})`** Navigate to a product, then select fields. ```julia # Navigate to users list, then select name/email from each nav = nested_tuple_nav([keypath("users"), ALL], [:name, :email]) data = Dict( "users" => [ (name="Alice", age=30, email="[email protected]"), (name="Bob", age=25, email="[email protected]") ] ) result = nav_select(nav, data, identity) # => [ # (name="Alice", email="[email protected]"), # (name="Bob", email="[email protected]") # ] ``` ### Field Projection **`project_tuple_nav(nav::TupleNav, fields::Vector{Symbol})`** Extract subset of fields from a TupleNav. ```julia nav_full = @tuple_nav([:id, :name, :age, :email]) nav_subset = project_tuple_nav(nav_full, [:name, :email]) # New navigator accesses only name and email ``` ## Structural Composition **Key insight**: TupleNav maintains **type safety across composition**. ```julia # Type 1: Person Person = NamedTuple{(:name, :age)} # Type 2: Contact Contact = NamedTuple{(:email, :phone)} # Type 3: User (combines both) User = NamedTuple{(:name, :age, :email, :phone)} # Composition is type-safe nav_person = @tuple_nav([:name, :age], Person) nav_contact = @tuple_nav([:email, :phone], Contact) nav_user = compose_tuple_navs(nav_person, nav_contact) # => TupleNav for User type ✓ ``` ## Parallel Semantics With `:parallel` strategy, all fields are accessed **in parallel** (logically): ```julia nav = @tuple_nav([:x, :y, :z], strategy=:parallel) # Execution order doesn't matter—all fields see the same input result1 = nav_select(nav, structure, f) result2 = nav_select(nav, structure, f) # => Always identical (deterministic parallel access) ``` Under the hood, this uses **color-aware SplitMix64 seeding** to ensure parallel reads remain deterministic (see `color-envelope-preserving` skill). ## Dictionary Projection TupleNav also works on dictionaries with structured keys: ```julia nav = @tuple_nav([:user_id, :user_name, :user_email]) data = Dict( :user_id => 42, :user_name => "Alice", :user_email => "[email protected]", :user_age => 30 ) result = nav_select(nav, data, identity) # => Dict(:user_id => 42, :user_name => "Alice", :user_email => "[email protected]") ``` ## Integration with Type Inference TupleNav output types are **automatically inferred** by the type system: ```julia nav = @tuple_nav([:x, :y, :z]) # Type: (T1, T2, T3) → (T1', T2', T3') # where T_i' is the refined type of field i sig = navigator_signature(nav) # => TypeSignature( # input: NamedTuple{(:x,:y,:z)}, # output: NamedTuple{(:x,:y,:z)}, # same structure # preserves: field types # ) ``` ## Composition with Constraints TupleNav can apply navigators to each field: ```julia # Each field goes through its own Navigator field_navs = Dict( :x => @late_nav([pred(ispositive)]), :y => @late_nav([pred(ispositive)]), :z => @late_nav([pred(ispositive)]) ) nav = @tuple_nav([:x, :y, :z], field_navigators=field_navs) # Each field must pass its predicate ``` ## Error Handling **Missing field**: ```julia nav = @tuple_nav([:name, :email, :phone]) person = (name="Alice", email="[email protected]") # missing :phone nav_select(nav, person, id) # => FieldMissingError("Field :phone not found in tuple") ``` **Type mismatch**: ```julia nav = @tuple_nav([:age]) # Expects numeric field person = (name="Alice", age="thirty") # age is string nav_select(nav, person, id) # => TypeError("Expected Int, got String for field :age") ``` ## Performance | Operation | Complexity | Notes | |-----------|-----------|-------| | Create TupleNav | O(n) | n = number of fields | | Parallel access | O(n) | All fields accessed once | | Sequential access | O(n²) | Each step threads to next | | Reduce | O(n) | Single fold over fields | | **Caching** | O(1) | Cache key includes field list | ## Related Skills - **type-inference-validation** - Validates field types at compile time - **constraint-generalization** - Combines field constraints across products - **specter-navigator-gadget** - Base Navigator system that TupleNav builds on - **möbius-path-filtering** - Ensures product navigation is topologically valid ## Use Cases **Example 1: Extract contact info from user records** ```julia nav = @tuple_nav([:name, :email, :phone]) users = [ (id=1, name="Alice", email="[email protected]", phone="555-1234"), (id=2, name="Bob", email="[email protected]", phone="555-5678") ] contacts = map(u -> nav_select(nav, u, identity), users) # All users' contact triples extracted ``` **Example 2: Parallel aggregation** ```julia nav = @tuple_nav([:revenue, :costs, :profit], strategy=:parallel) quarterly_data = ( revenue=100_000, costs=60_000, profit=40_000 ) result = nav_select(nav, quarterly_data, x -> x * 1.1) # 10% increase # => (revenue=110_000, costs=66_000, profit=44_000) ``` **Example 3: Nested product navigation** ```julia nav = nested_tuple_nav( [keypath("employees"), ALL], [:name, :salary] ) company = Dict( "employees" => [ (name="Alice", salary=80_000, dept="Engineering"), (name="Bob", salary=75_000, dept="Sales") ] ) result = nav_select(nav, company, identity) # => Extract name/salary for all employees ``` ## References - Product types: "Types and Programming Languages" - Pierce - Cartesian logic: "Basic Intuitionistic Linear Logic" - Girard - Parallel semantics: "Parallel Haskell" - Peyton Jones et al.