Claude Code Plugins

Community-maintained marketplace

Feedback

tuple-nav-composition

@plurigrid/asi
0
0

Tuple and product structure navigation with composition

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

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?

# Without TupleNav: Access fields separately, type mismatch risk
person = (name="Alice", age=30, email="alice@example.com")

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

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

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

nav = @tuple_nav([:x, :y, :z], strategy=:sequential)
# Field y receives result from x, z receives from y, etc.

:reduce - Fold/reduce across fields

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.

# Access name and email from person record
nav = @tuple_nav([:name, :email])

person = (name="Alice", email="alice@example.com", age=30)
result = nav_select(nav, person, identity)
# => (name="Alice", email="alice@example.com")

tuple_nav(fields::Vector{Symbol}, structure_type::Type) Explicitly typed TupleNav.

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.

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.

# 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="alice@example.com"),
    (name="Bob", age=25, email="bob@example.com")
  ]
)

result = nav_select(nav, data, identity)
# => [
#      (name="Alice", email="alice@example.com"),
#      (name="Bob", email="bob@example.com")
#    ]

Field Projection

project_tuple_nav(nav::TupleNav, fields::Vector{Symbol}) Extract subset of fields from a TupleNav.

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.

# 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):

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:

nav = @tuple_nav([:user_id, :user_name, :user_email])

data = Dict(
  :user_id => 42,
  :user_name => "Alice",
  :user_email => "alice@example.com",
  :user_age => 30
)

result = nav_select(nav, data, identity)
# => Dict(:user_id => 42, :user_name => "Alice", :user_email => "alice@example.com")

Integration with Type Inference

TupleNav output types are automatically inferred by the type system:

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:

# 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:

nav = @tuple_nav([:name, :email, :phone])
person = (name="Alice", email="alice@example.com")  # missing :phone

nav_select(nav, person, id)
# => FieldMissingError("Field :phone not found in tuple")

Type mismatch:

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

nav = @tuple_nav([:name, :email, :phone])
users = [
  (id=1, name="Alice", email="alice@ex.com", phone="555-1234"),
  (id=2, name="Bob", email="bob@ex.com", phone="555-5678")
]

contacts = map(u -> nav_select(nav, u, identity), users)
# All users' contact triples extracted

Example 2: Parallel aggregation

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

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.