diff --git a/libs/gram/src/Gram/Serialize.hs b/libs/gram/src/Gram/Serialize.hs index 7ad22bb..0290123 100644 --- a/libs/gram/src/Gram/Serialize.hs +++ b/libs/gram/src/Gram/Serialize.hs @@ -183,7 +183,7 @@ serializeLabels lbls | Set.null lbls = "" | otherwise = ":" ++ intercalate ":" (Set.toList lbls) - -- | Serialize a Subject to gram notation (legacy function, kept for compatibility). +-- | Serialize a Subject to gram notation (legacy function, kept for compatibility). -- Note: This always uses node syntax. Use toGram for proper syntax selection. serializeSubject :: Subject -> String serializeSubject (Subject ident lbls props) = @@ -192,14 +192,6 @@ serializeSubject (Subject ident lbls props) = serializeLabels lbls ++ serializePropertyRecord props --- | Serialize pattern elements for implicit root (no brackets/pipe). --- Used when serializing the top-level Gram container. --- NOTE: This function is now inlined into toGram to handle properties. --- Keeping signature for potential reuse or removing if unused. --- serializeImplicitElements :: [Pattern Subject] -> String --- serializeImplicitElements elems = --- intercalate "\n" (map toGram elems) - -- | Serialize pattern elements to gram notation. -- -- Converts a list of Pattern Subject elements to gram notation. diff --git a/specs/020-subject-serialization/contracts/api.md b/specs/020-subject-serialization/contracts/api.md index 166439d..9f2921d 100644 --- a/specs/020-subject-serialization/contracts/api.md +++ b/specs/020-subject-serialization/contracts/api.md @@ -19,5 +19,5 @@ fromGram :: String -> Either ParseError (Pattern Subject) ## Invariants 1. **Round-Trip**: `fromGram (toGram s) == Right s` (modulo potential ID generation for previously anonymous subjects, which become named). -2. **Identity**: `toGram` output for a Subject with ID `_anon_1` is `(_anon_1)` (or similar valid syntax). +2. **Identity**: `toGram` output for a Subject with ID `#1` is `(#1)` (or similar valid syntax). diff --git a/specs/020-subject-serialization/data-model.md b/specs/020-subject-serialization/data-model.md index 3a6be4a..f68c8bc 100644 --- a/specs/020-subject-serialization/data-model.md +++ b/specs/020-subject-serialization/data-model.md @@ -8,13 +8,13 @@ The core data structure representing a node or relationship's content. | Field | Type | Description | Constraints | |-------|------|-------------|-------------| -| `identity` | `Symbol` | Unique identifier | **Mandatory**. Cannot be empty string in a valid graph (though type allows it). Parsed anonymous subjects receive generated IDs (e.g., `_anon_1`). | +| `identity` | `Symbol` | Unique identifier | **Mandatory**. Cannot be empty string in a valid graph (though type allows it). Parsed anonymous subjects receive generated IDs (e.g., `#1`). | | `labels` | `Set String` | Classification tags | Unique set. | | `properties` | `Map String Value` | Key-value attributes | Keys are strings. Values are typed. | ### Identity Generation -- **Format**: `_anon_` +- **Format**: `#` (e.g., `#1`, `#2`, ...) - **Scope**: Local to a single `fromGram` parse operation. - **Counter**: Starts at 1 for each parse. diff --git a/specs/020-subject-serialization/research.md b/specs/020-subject-serialization/research.md index cdafab6..49c96d3 100644 --- a/specs/020-subject-serialization/research.md +++ b/specs/020-subject-serialization/research.md @@ -14,12 +14,12 @@ 2. **Sequential IDs (Global)**: Use a global counter. * *Pros*: Simple. * *Cons*: Requires `IO` / `MVar` / global state. Breaks purity. -3. **Sequential IDs (Local/Deterministic)**: Use a counter scoped to the `fromGram` call (e.g., `_anon_1`, `_anon_2`). +3. **Sequential IDs (Local/Deterministic)**: Use a counter scoped to the `fromGram` call (e.g., `#1`, `#2`). * *Pros*: Pure, deterministic, easy to test. * *Cons*: IDs are only unique within that specific parse result. Merging two parsed graphs could cause collisions if not handled (but that's a separate concern; `Subject` semigroup handles merging). **Decision**: **Option 3: Sequential IDs (Local/Deterministic)**. -We will generate IDs of the form `_anon_` (or similar distinct prefix) using a `State` monad during the transformation phase (`Gram.Transform`). +We will generate IDs of the form `#` using a `State` monad during the transformation phase (`Gram.Transform`). **Implementation Details**: - Modify `transformGram` to be `transformGram :: CST.Gram -> P.Pattern S.Subject` (keeping signature pure) but internally use `evalState` with a stateful transformation function. @@ -30,7 +30,7 @@ We will generate IDs of the form `_anon_` (or similar distinct prefix) using transformIdentifier Nothing = do n <- get put (n + 1) - return $ S.Symbol ("_anon_" ++ show n) + return $ S.Symbol ("#" ++ show n) transformIdentifier (Just (CST.IdentSymbol (CST.Symbol s))) = return $ S.Symbol s -- ... ``` @@ -38,8 +38,8 @@ We will generate IDs of the form `_anon_` (or similar distinct prefix) using ## 2. Round-trip Consistency **Context**: We want `fromGram . toGram == id` (conceptually). -If we parse `()` -> `Subject "_anon_1"`, then `toGram` will produce `(_anon_1)`. -Parsing `(_anon_1)` -> `Subject "_anon_1"`. +If we parse `()` -> `Subject "#1"`, then `toGram` will produce `(#1)`. +Parsing `(#1)` -> `Subject "#1"`. This preserves the data identity. **Decision**: Accept that anonymous subjects become named subjects after a round-trip. This is consistent with the requirement that `Subject` *has* an identity. The "anonymous" syntax is just a shorthand for "I don't care about the ID, make one up". Once made up, it persists.