Skip to content

Commit 68c5bba

Browse files
committed
Merge branch 'main' of github.com:relateby/pattern-hs
2 parents be5451f + 434829e commit 68c5bba

23 files changed

Lines changed: 2515 additions & 1 deletion

proposals/design/DESIGN.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Patterns as Graph Views: A Categorical Framework
22

3+
> **Superseded by [RFC-002: Pattern as Container and Graph Substrate](RFC-002-pattern-container-substrate.md)**
4+
>
5+
> This document is retained for historical reference. RFC-002 consolidates the content
6+
> here with `pattern-category.md`, removes stale "⏳ Planned" markers, and reorganises
7+
> into the standard RFC format.
8+
39
**Status**: ✅ Implemented
410
**Implementation**: Core Pattern type and typeclass instances are implemented. Graph Lens (Feature 23) is implemented. Some planned features (Zipper, Pattern Morphisms) are deferred.
511

proposals/design/EXTENDED-SEMANTICS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Gram Extended Semantics: Pattern and Path Notation
22

3+
> **Superseded by [RFC-003: Gram Notation Semantics](RFC-003-gram-notation-semantics.md)**
4+
>
5+
> This document is retained for historical reference. RFC-003 merges this document with
6+
> `SEMANTICS.md` into a single authoritative reference for gram notation semantics.
7+
38
**Status**: ✅ Implemented
49
**Implementation**: Gram serialization and parsing support both pattern and path notation
510
**Reference**: See `docs/reference/semantics/gram-semantics.md` for current specification

proposals/design/README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Design RFCs — pattern-hs
2+
3+
This directory contains the authoritative design documents for pattern-hs, organized
4+
as numbered RFCs. Each RFC follows a standard format: Status, Summary, Motivation,
5+
Design, Open Questions, Alternatives.
6+
7+
## RFC Index
8+
9+
### Foundation (Accepted — Implemented)
10+
11+
| RFC | Title | Status | Key Modules |
12+
|-----|-------|--------|-------------|
13+
| [RFC-002](RFC-002-pattern-container-substrate.md) | Pattern as Container and Graph Substrate | accepted | `Pattern.Core`, `Pattern.Graph.GraphLens` |
14+
| [RFC-003](RFC-003-gram-notation-semantics.md) | Gram Notation Semantics | accepted | `Gram.Core`, `Gram.Parser` |
15+
| [RFC-010](RFC-010-pattern-reconciliation.md) | Pattern Reconciliation | accepted | `Pattern.Reconcile`, `Subject.Core` |
16+
17+
### Active Design (Draft — In Progress)
18+
19+
| RFC | Title | Status | Key Modules |
20+
|-----|-------|--------|-------------|
21+
| [RFC-001](RFC-001-strata-and-aspects.md) | Strata and Aspects | draft | `Pattern.Stratum`, `Pattern.Aspect` |
22+
23+
### Graph Interface Layer (Draft — Design)
24+
25+
| RFC | Title | Status | Depends on |
26+
|-----|-------|--------|------------|
27+
| [RFC-004](RFC-004-graph-classifier.md) | GraphClassifier — Unified Graph View | draft ||
28+
| [RFC-005](RFC-005-graph-query.md) | GraphQuery — Portable Query Interface | draft | RFC-004 |
29+
| [RFC-006](RFC-006-scope-unification.md) | Scope Unification — ScopeQuery and paraWithScope | draft | RFC-005 |
30+
| [RFC-007](RFC-007-representation-map.md) | RepresentationMap — Invertible Shape Isomorphisms | draft | RFC-006, RFC-008 |
31+
| [RFC-008](RFC-008-graph-transform.md) | GraphTransform — Construction, Transformation, Pipeline | draft | RFC-004, RFC-005 |
32+
| [RFC-009](RFC-009-graph-mutation.md) | GraphMutation — Coherent In-Memory Graph Mutations | draft | RFC-004, RFC-005, RFC-008 |
33+
34+
## Implementation Order
35+
36+
The graph interface RFCs form a dependency chain:
37+
38+
```
39+
RFC-004 (GraphClassifier)
40+
└── RFC-005 (GraphQuery)
41+
├── RFC-006 (ScopeQuery) ──→ RFC-007 (RepresentationMap)
42+
└── RFC-008 (GraphTransform)
43+
└── RFC-009 (GraphMutation)
44+
```
45+
46+
RFC-007 (RepresentationMap) additionally depends on RFC-008 (GraphTransform) being
47+
settled first, since it builds on `paraWithScope` and the GraphTransform primitives.
48+
49+
RFC-010 (Pattern Reconciliation) is accepted and implemented independently of the
50+
graph interface chain.
51+
52+
## Superseded Documents
53+
54+
The following documents in this directory have been superseded by RFCs and are retained
55+
for historical reference only:
56+
57+
| File | Superseded by |
58+
|------|---------------|
59+
| [DESIGN.md](DESIGN.md) | RFC-002 |
60+
| [SEMANTICS.md](SEMANTICS.md) | RFC-003 |
61+
| [EXTENDED-SEMANTICS.md](EXTENDED-SEMANTICS.md) | RFC-003 |
62+
| [pattern-category.md](pattern-category.md) | RFC-002 |
63+
64+
The following documents in `proposals/` (parent directory) are similarly superseded:
65+
66+
| File | Superseded by |
67+
|------|---------------|
68+
| `proposals/graph-classifier.md` | RFC-004 |
69+
| `proposals/graph-query.md` | RFC-005 |
70+
| `proposals/scope-unification-proposal.md` | RFC-006 |
71+
| `proposals/representation-map-proposal.md` | RFC-006 + RFC-007 |
72+
| `proposals/graph-transform.md` | RFC-008 |
73+
| `proposals/pipeline-scenarios.md` | RFC-008 |
74+
| `proposals/graph-mutation.md` | RFC-009 |
75+
| `proposals/pattern-reconciliation.md` | RFC-010 |
76+
77+
## Non-RFC Documents
78+
79+
The following documents in this directory serve specific purposes and are not RFCs:
80+
81+
| File | Purpose |
82+
|------|---------|
83+
| [pattern-basic-aspects-review.md](pattern-basic-aspects-review.md) | Implementation reference: `length`, `size`, `depth` query functions |
84+
| [graph-lens.md](graph-lens.md) | Implementation notes for the `GraphLens` feature |
85+
| [gram-hs-cli-improvements.md](gram-hs-cli-improvements.md) | CLI tool improvement proposals |
86+
| [gram-hs-cli-plan.md](gram-hs-cli-plan.md) | CLI tool implementation plan |
87+
| [pattern-matching-dsl-design.md](pattern-matching-dsl-design.md) | Pattern matching DSL exploration |
88+
89+
The following document in `proposals/` is a pre-RFC stub pending full design:
90+
91+
| File | Status |
92+
|------|--------|
93+
| `proposals/pattern-equivalence.md` | Pre-RFC: motivating examples only; needs full design |
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# RFC-002: Pattern as Container and Graph Substrate
2+
3+
**Status:** accepted
4+
**Date:** 2025-11-01
5+
**Authors:** @akollegger
6+
**Repository:** [github.com/relateby/pattern-hs](https://github.com/relateby/pattern-hs)
7+
**Supersedes:** [`proposals/design/DESIGN.md`](DESIGN.md), [`proposals/design/pattern-category.md`](pattern-category.md)
8+
**Related modules:** `Pattern.Core`, `Pattern.Graph.GraphLens`, `Pattern.PatternGraph`
9+
10+
## Summary
11+
12+
`Pattern v` is a recursive decorated-sequence container: a value paired with an ordered
13+
list of element Patterns. It is not itself a graph; graph structure is an *interpretation*
14+
imposed by external machinery. The same `Pattern v` can be interpreted as a directed graph,
15+
an undirected graph, a walk, or any other graph-like structure depending on which view is
16+
applied. This separation of container from interpretation is the load-bearing design choice
17+
that enables flexibility across graph semantics without committing to any single one.
18+
19+
## Motivation
20+
21+
Graph data structures traditionally encode semantic commitments in their types: a
22+
`DiGraph` is directed, an `UndirectedGraph` is not, a `WeightedGraph` carries edge
23+
weights. This forces users to choose an interpretation at construction time and makes
24+
multiple simultaneous interpretations cumbersome.
25+
26+
`Pattern v` inverts this: a universal container accumulates structure, and views impose
27+
interpretations on demand. The same Pattern that represents a person's professional
28+
network can simultaneously represent their social graph, their org chart, or a sequence
29+
of career transitions — without duplicating data. The interpretation that is salient
30+
depends on the question being asked, not on how the data was originally stored.
31+
32+
This is the motivation for separating substrate from interpretation.
33+
34+
## Design
35+
36+
### The Pattern Data Structure
37+
38+
```haskell
39+
data Pattern v = Pattern
40+
{ value :: v -- decoration: what kind of pattern this is
41+
, elements :: [Pattern v] -- the pattern's content, as an ordered sequence
42+
}
43+
```
44+
45+
Patterns are recursive: every element of a Pattern is itself a Pattern. The `elements`
46+
field is the sequence that defines the pattern's content; the `value` field is a
47+
decoration that describes what the sequence means.
48+
49+
**Key insight**: The elements field IS the pattern it contains the sequence that defines
50+
the content. The value field decorates that content. For example, a pattern `[chord | C, E, G]`
51+
has value `chord` decorating the sequence `[C, E, G]`.
52+
53+
### Conceptual Model: Decorated Sequences
54+
55+
Conceptually, patterns are **decorated sequences**:
56+
- `elements` holds the sequence that defines the pattern
57+
- `value` provides decoration about what kind of pattern it is
58+
- Order of elements is semantically significant patterns are ordered
59+
- Recursive structure enables nested sequences (patterns containing patterns)
60+
61+
The tree structure is an implementation detail that supports sequences in memory. There
62+
is no contradiction between these views the tree structure is how sequences are
63+
represented, and tree traversal preserves sequence order.
64+
65+
### Structural Classifications
66+
67+
Patterns have structural classifications based on element count. These describe what
68+
patterns *are* structurally, independent of any interpretation.
69+
70+
**Atomic Pattern** `elements == []`. The fundamental building block; the leaf of any
71+
Pattern tree. Nodes in the graph interpretation are atomic patterns.
72+
73+
**Singular Pattern** exactly one element. A pattern wrapping a single sub-pattern.
74+
75+
**Pattern with Elements** one or more elements. The general case.
76+
77+
**Nested Pattern** elements that themselves have elements, enabling arbitrary depth.
78+
79+
### Graph Interpretations
80+
81+
Patterns are *interpreted* as graph elements through views. The same structural
82+
classification rules apply across all interpretations.
83+
84+
#### Nodes
85+
86+
A node is an atomic pattern a Pattern with no elements.
87+
88+
```haskell
89+
node :: v -> Pattern v
90+
node v = Pattern v []
91+
```
92+
93+
Notation equivalences:
94+
```
95+
Cypher: (n:Person)
96+
Pattern: [n:Person]
97+
```
98+
99+
#### Relationships
100+
101+
**Undirected**: a pattern with exactly two atomic elements; order is semantically irrelevant.
102+
**Directed**: a pattern with exactly two atomic elements, where element order encodes direction —
103+
`element[0]` is the source, `element[1]` is the target.
104+
105+
```haskell
106+
-- Source/target accessors
107+
source :: Pattern v -> Pattern v
108+
source (Pattern _ (s:_)) = s
109+
110+
target :: Pattern v -> Pattern v
111+
target (Pattern _ [_, t]) = t
112+
113+
-- Reverse direction
114+
reverseRel :: Pattern v -> Pattern v
115+
reverseRel (Pattern v [a, b]) = Pattern v [b, a]
116+
```
117+
118+
Notation equivalences:
119+
```
120+
Cypher: (a)-[r:KNOWS]->(b) Pattern: [r:KNOWS | a, b] -- directed, a→b
121+
Cypher: (a)<-[r:KNOWS]-(b) Pattern: [r:KNOWS | b, a] -- directed, b→a
122+
Cypher: (a)-[r:KNOWS]-(b) Pattern: [r:KNOWS | a, b] -- undirected (order irrelevant)
123+
```
124+
125+
**Design rationale**: direction is encoded positionally in the existing ordered-sequence
126+
structure, with no extra type machinery. Reversing a relationship is a structural
127+
operation: swap the two elements. Directed vs. undirected is a semantic distinction
128+
managed by the consumer, not a structural one.
129+
130+
#### Walks
131+
132+
A walk is an ordered sequence of relationships allowing continuous traversal: entering
133+
each relationship at one endpoint and exiting at the other, which becomes the entry
134+
point of the next relationship.
135+
136+
```haskell
137+
walk :: v -> [Pattern v] -> Pattern v
138+
walk meta relationships = Pattern meta relationships
139+
```
140+
141+
```
142+
Cypher: (a)-[r1]->(b)<-[r2]-(c)-[r3]->(d)
143+
Pattern: [walk | [r1 | a, b], [r2 | c, b], [r3 | c, d]]
144+
```
145+
146+
Valid walk compositions in Pattern notation:
147+
```
148+
[w | [r1 | a, b]] =~ (a)-[r1]->(b)
149+
[w | [r1 | a, b], [r2 | c, b]] =~ (a)-[r1]->(b)<-[r2]-(c)
150+
[w | [r1 | a, b], [r2 | b, a]] =~ (a)-[r1]->(b)-[r2]->(a)
151+
```
152+
153+
#### Summary
154+
155+
| Concept | Pattern Structure | Convention |
156+
|----------------|------------------------------|-------------------------------------|
157+
| Node | `[v]` | Atomic pattern (no elements) |
158+
| Undirected Rel | `[r \| (a), (b)]` | Order semantically irrelevant |
159+
| Directed Rel | `[r \| (a), (b)]` | element[0]=source, element[1]=target |
160+
| Walk | `[meta \| rel1, rel2, ...]` | Consecutive rels share endpoints |
161+
162+
### Typeclass Instances
163+
164+
`Pattern v` is implemented with the following typeclass instances (all accepted):
165+
166+
- `Functor` — structure-preserving map over values: `fmap f` transforms every `v` while
167+
preserving the Pattern tree structure
168+
- `Foldable` — fold over all values in traversal order
169+
- `Traversable` — effectful traversal, combining Functor and Foldable
170+
- `Applicative` — zip-like application of a Pattern of functions to a Pattern of values
171+
- `Comonad``extract` retrieves the root value; `extend` maps with local context;
172+
`duplicate` produces the Pattern of all sub-Patterns
173+
- `Eq`, `Ord`, `Hashable` — structural equality, ordering, and hashing
174+
- `Semigroup`, `Monoid` — Pattern combination with identity
175+
- `Show`, `ToJSON`, `FromJSON` — display and serialization
176+
177+
### Category-Theoretic Perspective
178+
179+
`Pattern v` admits a categorical interpretation through a `CategoryLens`, which defines
180+
what counts as objects and how values compose:
181+
182+
```haskell
183+
data CategoryLens v = CategoryLens
184+
{ valueOp :: v -> v -> v -- value composition (magma operation)
185+
, isObject :: Pattern v -> Bool -- which patterns are objects
186+
}
187+
```
188+
189+
Under a graph lens, leaf patterns (atoms) are objects and arity-2 patterns are morphisms.
190+
Objects and morphisms are identified *post-hoc* through predicates, not enforced at
191+
construction time.
192+
193+
**Composition** preserves structure rather than flattening:
194+
195+
```haskell
196+
compose :: (v -> v -> v) -> Pattern v -> Pattern v -> Pattern v
197+
compose f (Pattern v1 elems1) (Pattern v2 elems2) =
198+
Pattern (f v1 v2) [Pattern v1 elems1, Pattern v2 elems2]
199+
```
200+
201+
The original patterns become elements of the composite, maintaining internal structure.
202+
203+
**Morphism equivalence** — two patterns are equivalent as morphisms when they have the
204+
same leaf sequence (same objects in sequence order). Three levels:
205+
206+
- *Structural equivalence*: same complete leaf sequence
207+
- *Endpoint equivalence*: same source and target objects (hom-set membership)
208+
- *Custom*: domain-specific equivalence relation
209+
210+
**The category is not intrinsic to `Pattern`**; it emerges from the chosen lens. The
211+
same `Pattern v` can support many different categorical structures by varying the lens,
212+
validity rules, or equivalence relation. This is the "schema-lazy" property: maximum
213+
flexibility during construction, multiple valid interpretations on demand.
214+
215+
### Forgetful Functor Hierarchy
216+
217+
Views form a hierarchy of forgetful functors, each losing information as it descends:
218+
219+
```
220+
Pat[Full] --F₁--> Pat[Shape] --F₂--> Pat[Topology] --F₃--> Pat[Connected]
221+
```
222+
223+
```haskell
224+
forgetValues :: Pattern v -> Pattern ()
225+
forgetValues = fmap (const ())
226+
```
227+
228+
This enables analogical reasoning: match patterns that are structurally similar under
229+
some forgetting, even if their values differ.
230+
231+
### Key Properties
232+
233+
1. **Schema-lazy** — Patterns do not commit to specific graph semantics; interpretation
234+
happens in the view. The same Pattern is valid under any compatible view.
235+
2. **Compositional** — Views can be composed, stacked, or swapped without changing
236+
underlying patterns.
237+
3. **Open-ended** — New views can be defined for any graph-like interpretation.
238+
4. **Categorical** — Each view defines a functor; forgetful matching uses functor
239+
composition.
240+
241+
## Open Questions
242+
243+
1. **Navigation functions**`source`, `target`, `nodes`, `relationships` as explicit
244+
Pattern operations are planned but not implemented. They would provide ergonomic
245+
access to graph-structured patterns without requiring a full view.
246+
247+
2. **Zipper for focus** — A `Zipper v` data structure supporting `parents` /
248+
`ancestors` operations would enable DOM-style upward navigation and focus-based
249+
editing. Currently deferred; comonadic `extend` and `duplicate` partially address
250+
the use cases.
251+
252+
3. **Pattern morphisms** — Explicit `PatternMorphism v w` types with `homomorphism`
253+
and `forget` combinators are planned as future work for categorical reasoning.
254+
255+
4. **Standard view instances** — Named instances like `DirectedView` and `UndirectedView`
256+
are planned to reduce boilerplate for the common cases.
257+
258+
## Alternatives
259+
260+
**Typed graph representations** — encoding node/relationship/walk distinction in the
261+
type system (e.g. GADTs indexed by sort) was rejected. `Pattern v`'s uniform-value
262+
architecture is load-bearing for typeclass instances, and sort indexing would require
263+
either a parallel type or a substantial rewrite. The runtime cost of kind predicates
264+
is acceptable.
265+
266+
**Forcing interpretation at construction** — building a `Graph` type with committed
267+
semantics at the constructor site was rejected in favor of the substrate posture.
268+
Post-hoc interpretation via views is more flexible without being more complex.

0 commit comments

Comments
 (0)