Skip to content

Commit 1973aa9

Browse files
committed
bug: fixed pattern depth so atomic patterns (patterns with no elements) are depth 0
1 parent 424fd15 commit 1973aa9

3 files changed

Lines changed: 344 additions & 11 deletions

File tree

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
# Pattern Basic Aspects Review: Depth, Size, and Length
2+
3+
**Date**: 2025-01-27
4+
**Purpose**: Review and illustrate basic pattern aspects using gram notation
5+
6+
## Current Implementation
7+
8+
### 1. `length :: Pattern v -> Int`
9+
10+
**Definition**: Returns the number of direct elements in a pattern's sequence.
11+
12+
**Implementation**:
13+
```haskell
14+
length :: Pattern v -> Int
15+
length (Pattern _ es) = Prelude.length es
16+
```
17+
18+
**Properties**:
19+
- O(1) operation
20+
- Counts only direct children, not nested descendants
21+
- Atomic patterns (no elements) return 0
22+
23+
### 2. `size :: Pattern v -> Int`
24+
25+
**Definition**: Returns the total number of nodes in a pattern structure.
26+
27+
**Implementation**:
28+
```haskell
29+
size :: Pattern v -> Int
30+
size (Pattern _ es) = 1 + sum (map size es)
31+
```
32+
33+
**Properties**:
34+
- O(n) operation where n is the total number of nodes
35+
- Recursively counts all nodes at all nesting levels
36+
- Includes the root node
37+
- Atomic patterns return 1
38+
39+
### 3. `depth :: Pattern v -> Int`
40+
41+
**Definition**: Returns the maximum nesting depth of a pattern structure.
42+
43+
**Implementation**:
44+
```haskell
45+
depth :: Pattern v -> Int
46+
depth (Pattern _ []) = 0
47+
depth (Pattern _ es) = 1 + maximum (map depth es)
48+
```
49+
50+
**Properties**:
51+
- O(n) operation where n is the total number of nodes
52+
- Atomic patterns return 0 (zero-based depth, root only, no nesting)
53+
- Pattern with elements has depth 1 + max depth of elements
54+
- Returns maximum depth across all branches
55+
- Follows standard tree depth conventions (root at depth 0)
56+
57+
## Gram Notation Examples
58+
59+
Gram notation uses subject pattern syntax `[ subject | elements ]` to represent patterns. The following examples illustrate how depth, size, and length work with various pattern structures.
60+
61+
### Example 1: Atomic Pattern
62+
63+
**Gram Notation**:
64+
```gram
65+
[atom]
66+
```
67+
68+
**Structure**: A single pattern with no elements
69+
- `value`: `atom`
70+
- `elements`: `[]`
71+
72+
**Metrics**:
73+
- `length`: 0 (no direct elements)
74+
- `size`: 1 (just the root node)
75+
- `depth`: 0 (atomic pattern, zero-based depth)
76+
77+
**Visualization**:
78+
```
79+
[atom]
80+
└─ (no elements)
81+
```
82+
83+
### Example 2: Simple Sequence
84+
85+
**Gram Notation**:
86+
```gram
87+
[sequence | a, b, c]
88+
```
89+
90+
**Structure**: A pattern with three direct elements
91+
- `value`: `sequence`
92+
- `elements`: `[a, b, c]` (each is an atomic pattern)
93+
94+
**Metrics**:
95+
- `length`: 3 (three direct elements: a, b, c)
96+
- `size`: 4 (root + 3 atomic elements = 1 + 1 + 1 + 1)
97+
- `depth`: 1 (root has elements, each element has depth 0, so root depth = 1 + max(0,0,0) = 1)
98+
99+
**Visualization**:
100+
```
101+
[sequence]
102+
├─ [a]
103+
├─ [b]
104+
└─ [c]
105+
```
106+
107+
### Example 3: Nested Pattern (One Level)
108+
109+
**Gram Notation**:
110+
```gram
111+
[root | [inner | x, y]]
112+
```
113+
114+
**Structure**: A pattern containing one nested pattern
115+
- `value`: `root`
116+
- `elements`: `[[inner | x, y]]` (one element which is itself a pattern)
117+
118+
**Metrics**:
119+
- `length`: 1 (one direct element: the inner pattern)
120+
- `size`: 4 (root + inner + x + y = 1 + 1 + 1 + 1)
121+
- `depth`: 2 (root depth = 1 + max(inner depth) where inner depth = 1 + max(0,0) = 1, so root = 1 + 1 = 2)
122+
123+
**Visualization**:
124+
```
125+
[root]
126+
└─ [inner]
127+
├─ [x]
128+
└─ [y]
129+
```
130+
131+
### Example 4: Multiple Nested Patterns
132+
133+
**Gram Notation**:
134+
```gram
135+
[container | [left | a, b], [right | c, d]]
136+
```
137+
138+
**Structure**: A pattern with two nested patterns
139+
- `value`: `container`
140+
- `elements`: `[[left | a, b], [right | c, d]]`
141+
142+
**Metrics**:
143+
- `length`: 2 (two direct elements: left and right patterns)
144+
- `size`: 6 (root + left + a + b + right + c + d = 1 + 1 + 1 + 1 + 1 + 1 + 1)
145+
- `depth`: 2 (root depth = 1 + max(left depth, right depth) where both left and right have depth = 1 + max(0,0) = 1, so root = 1 + 1 = 2)
146+
147+
**Visualization**:
148+
```
149+
[container]
150+
├─ [left]
151+
│ ├─ [a]
152+
│ └─ [b]
153+
└─ [right]
154+
├─ [c]
155+
└─ [d]
156+
```
157+
158+
### Example 5: Deeply Nested Pattern
159+
160+
**Gram Notation**:
161+
```gram
162+
[level1 | [level2 | [level3 | [level4 | leaf]]]]
163+
```
164+
165+
**Structure**: A linear chain of nested patterns
166+
- `value`: `level1`
167+
- `elements`: `[[level2 | [level3 | [level4 | leaf]]]]`
168+
169+
**Metrics**:
170+
- `length`: 1 (one direct element: level2)
171+
- `size`: 5 (level1 + level2 + level3 + level4 + leaf = 5 nodes)
172+
- `depth`: 4 (calculated as: leaf=0, level4=1+0=1, level3=1+1=2, level2=1+2=3, level1=1+3=4)
173+
174+
**Visualization**:
175+
```
176+
[level1]
177+
└─ [level2]
178+
└─ [level3]
179+
└─ [level4]
180+
└─ [leaf]
181+
```
182+
183+
### Example 6: Asymmetric Branching
184+
185+
**Gram Notation**:
186+
```gram
187+
[root | [shallow | a], [deep | [deeper | [deepest | x]]]]
188+
```
189+
190+
**Structure**: A pattern with branches of different depths
191+
- `value`: `root`
192+
- `elements`: `[[shallow | a], [deep | [deeper | [deepest | x]]]]`
193+
194+
**Metrics**:
195+
- `length`: 2 (two direct elements: shallow and deep)
196+
- `size`: 7 (root + shallow + a + deep + deeper + deepest + x = 7 nodes)
197+
- `depth`: 4 (calculated as: [x]=0, [deepest|x]=1+0=1, [deeper|...]=1+1=2, [deep|...]=1+2=3, [shallow|a]=1+0=1, [root|...]=1+max(1,3)=4)
198+
199+
**Visualization**:
200+
```
201+
[root]
202+
├─ [shallow]
203+
│ └─ [a]
204+
└─ [deep]
205+
└─ [deeper]
206+
└─ [deepest]
207+
└─ [x]
208+
```
209+
210+
### Example 7: Graph Node Pattern (Atomic)
211+
212+
**Gram Notation**:
213+
```gram
214+
(a:Person {name: "Alice"})
215+
```
216+
217+
**Structure**: A node pattern (syntactic sugar for atomic pattern)
218+
- `value`: Subject with identifier `a`, label `Person`, and properties
219+
- `elements`: `[]` (nodes are atomic)
220+
221+
**Metrics**:
222+
- `length`: 0 (no elements)
223+
- `size`: 1 (just the node)
224+
- `depth`: 0 (atomic pattern, zero-based depth)
225+
226+
### Example 8: Relationship Pattern
227+
228+
**Gram Notation**:
229+
```gram
230+
(a)-[r:KNOWS]->(b)
231+
```
232+
233+
**Structure**: A relationship pattern (syntactic sugar)
234+
- This desugars to: `[r:KNOWS | (a), (b)]`
235+
- `value`: Subject with identifier `r` and label `KNOWS`
236+
- `elements`: `[(a), (b)]` (two node patterns)
237+
238+
**Metrics**:
239+
- `length`: 2 (two direct elements: nodes a and b)
240+
- `size`: 3 (relationship + node a + node b)
241+
- `depth`: 1 (relationship has elements, each node has depth 0, so relationship depth = 1 + max(0,0) = 1)
242+
243+
### Example 9: Subject with Members
244+
245+
**Gram Notation**:
246+
```gram
247+
[team:Team {name: "DevRel"} | abk, adam, alex]
248+
```
249+
250+
**Structure**: A subject pattern with identifier, label, properties, and elements
251+
- `value`: Subject with identifier `team`, label `Team`, and properties
252+
- `elements`: `[abk, adam, alex]` (three atomic patterns)
253+
254+
**Metrics**:
255+
- `length`: 3 (three direct elements: abk, adam, alex)
256+
- `size`: 4 (team + abk + adam + alex)
257+
- `depth`: 1 (team has elements, each member has depth 0, so team depth = 1 + max(0,0,0) = 1)
258+
259+
### Example 10: Complex Nested Structure
260+
261+
**Gram Notation**:
262+
```gram
263+
[organization |
264+
[engineering:Team |
265+
[backend:Group | alice, bob],
266+
[frontend:Group | charlie, diana]
267+
],
268+
[product:Team |
269+
[design:Group | eve],
270+
[research:Group | frank, grace]
271+
]
272+
]
273+
```
274+
275+
**Structure**: Multi-level nested organization
276+
- `value`: `organization`
277+
- `elements`: Two team patterns, each containing group patterns
278+
279+
**Metrics**:
280+
- `length`: 2 (two direct elements: engineering and product teams)
281+
- `size`: 13 (organization + engineering + backend + alice + bob + frontend + charlie + diana + product + design + eve + research + frank + grace)
282+
- `depth`: 3 (calculated as: members=0, groups=1+max(0,0)=1, teams=1+max(1,1)=2, organization=1+max(2,2)=3)
283+
284+
**Visualization**:
285+
```
286+
[organization]
287+
├─ [engineering:Team]
288+
│ ├─ [backend:Group]
289+
│ │ ├─ [alice]
290+
│ │ └─ [bob]
291+
│ └─ [frontend:Group]
292+
│ ├─ [charlie]
293+
│ └─ [diana]
294+
└─ [product:Team]
295+
├─ [design:Group]
296+
│ └─ [eve]
297+
└─ [research:Group]
298+
├─ [frank]
299+
└─ [grace]
300+
```
301+
302+
## Summary Table
303+
304+
| Example | Gram Pattern | length | size | depth |
305+
|---------|-------------|--------|------|-------|
306+
| Atomic | `[atom]` | 0 | 1 | 0 |
307+
| Simple sequence | `[seq \| a, b, c]` | 3 | 4 | 1 |
308+
| One level nested | `[root \| [inner \| x, y]]` | 1 | 4 | 2 |
309+
| Multiple nested | `[container \| [left \| a, b], [right \| c, d]]` | 2 | 6 | 2 |
310+
| Deep nesting | `[l1 \| [l2 \| [l3 \| [l4 \| leaf]]]]` | 1 | 5 | 4 |
311+
| Asymmetric | `[root \| [shallow \| a], [deep \| [deeper \| [deepest \| x]]]]` | 2 | 7 | 4 |
312+
| Node | `(a:Person {name: "Alice"})` | 0 | 1 | 0 |
313+
| Relationship | `(a)-[r:KNOWS]->(b)` | 2 | 3 | 1 |
314+
| Team | `[team:Team {name: "DevRel"} \| abk, adam, alex]` | 3 | 4 | 1 |
315+
| Complex org | Multi-level structure | 2 | 13 | 3 |
316+
317+
## Key Insights
318+
319+
1. **Length** measures only direct children, making it useful for understanding immediate structure.
320+
321+
2. **Size** measures total nodes, making it useful for understanding overall complexity and memory usage.
322+
323+
3. **Depth** measures maximum nesting, making it useful for understanding structural complexity and recursion limits.
324+
325+
4. **Relationship between metrics**:
326+
- `size >= length + 1` (size includes root, length doesn't)
327+
- `depth >= 0` (all patterns have at least depth 0, atomic patterns have depth 0)
328+
- For atomic patterns: `length = 0`, `size = 1`, `depth = 0`
329+
330+
5. **Gram notation mapping**:
331+
- Subject patterns `[subject \| elements]` directly map to Pattern structure
332+
- Node patterns `(subject)` are atomic patterns (length=0)
333+
- Relationship patterns `(a)-[r]->(b)` desugar to patterns with 2 elements
334+

libs/pattern/src/Pattern/Core.hs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -922,22 +922,22 @@ size (Pattern _ es) = 1 + sum (map size es)
922922

923923
-- | Returns the maximum nesting depth of a pattern structure.
924924
--
925-
-- An atomic pattern has depth 1.
925+
-- An atomic pattern has depth 0 (root only, no nesting).
926926
-- A pattern with elements has depth 1 + max depth of elements.
927927
-- This operation is O(n) where n is the total number of nodes.
928928
--
929929
-- === Examples
930930
--
931931
-- >>> depth (pattern "atom")
932-
-- 1
932+
-- 0
933933
--
934934
-- >>> depth (patternWith "root" [pattern "child"])
935-
-- 2
935+
-- 1
936936
--
937937
-- >>> depth (patternWith "root" [patternWith "middle" [pattern "inner"]])
938-
-- 3
938+
-- 2
939939
depth :: Pattern v -> Int
940-
depth (Pattern _ []) = 1
940+
depth (Pattern _ []) = 0
941941
depth (Pattern _ es) = 1 + maximum (map depth es)
942942

943943
-- | Extracts all values from a pattern structure as a flat list.
@@ -1110,17 +1110,15 @@ toTuple (Pattern v es) = (v, es)
11101110
-- | Computes the nesting depth at each position in the pattern.
11111111
--
11121112
-- Returns a new pattern with the same structure where each value is replaced
1113-
-- by its depth (distance from root + 1).
1113+
-- by its depth (maximum nesting depth of the subtree at that position).
11141114
--
11151115
-- === Examples
11161116
--
11171117
-- >>> p = patternWith "root" [pattern "child"]
11181118
-- >>> depthAt p
1119-
-- Pattern 1 [Pattern 2 []]
1119+
-- Pattern 1 [Pattern 0 []]
11201120
depthAt :: Pattern v -> Pattern Int
1121-
depthAt = go 1
1122-
where
1123-
go d (Pattern _ es) = Pattern d (map (go (d + 1)) es)
1121+
depthAt = extend depth
11241122

11251123
-- | Computes the size of the subtree at each position in the pattern.
11261124
--

specs/014-comonad-instance/data-model.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ depthAt = extend (\p -> depth p)
178178
**Example**:
179179
```haskell
180180
let p = patternWith "root" [pattern "a", pattern "b"]
181-
in depthAt p == pattern 0 [pattern 1, pattern 1] -- True
181+
in depthAt p == pattern 1 [pattern 0, pattern 0] -- True
182+
-- Root has depth 1 (one level of nesting), atomic children have depth 0
182183
```
183184

184185
### Size at Each Position

0 commit comments

Comments
 (0)