From c99fa839263915c5a902793ba6c5875db4942a44 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Nov 2025 23:19:57 +0000 Subject: [PATCH 1/7] Add NonNull types to RootedDeterministicPath and DPBranch Updated type definitions to use NonNull for guaranteed non-empty collections: - RootedDeterministicPath.rootBranches now uses NonNull (OMap ...) - DPBranch.DPSequence branch sets now use NonNull (OSet ...) Removed error cases that checked for empty sets: - Removed "invariant broken: rootBranches must be nonempty" error - Removed "invariant broken: both branch sets must be nonempty" error Updated all code using these types to work with NonNull: - smartBuildSequence now takes NonNull parameters - smartBuildRootedDeterministicPath now takes NonNull parameters - branchify returns NonNull sets - All construction sites wrap with impureNonNull - Parse functions updated to construct NonNull values - MaterializePath updated to handle NonNull conversions --- cli/src/Graph/MaterializePath.hs | 15 +-- cli/src/Models/NormalizedPath.hs | 130 ++++++++++++------------- cli/src/Models/NormalizedPath/Parse.hs | 12 +-- 3 files changed, 79 insertions(+), 78 deletions(-) diff --git a/cli/src/Graph/MaterializePath.hs b/cli/src/Graph/MaterializePath.hs index 1df9e075..5d0b5683 100644 --- a/cli/src/Graph/MaterializePath.hs +++ b/cli/src/Graph/MaterializePath.hs @@ -96,7 +96,7 @@ materializeNPath firstNid normalizedPath = do traverseRooted nid RootedDeterministicPath {..} = do rootBranches' :: [ [ ( DeterministicPath NID, - OSet (DPBranch FullyAnchored) + NonNull (OSet (DPBranch FullyAnchored)) ) ] ] <- @@ -106,15 +106,16 @@ materializeNPath firstNid normalizedPath = do <&> map (\(rs, bs) -> (,bs) <$> rs) <&> choices rootBranches'' :: - [(OMap (DeterministicPath NID) (OSet (DPBranch NID)), NID)] <- + [(OMap (DeterministicPath NID) (NonNull (OSet (DPBranch NID))), NID)] <- rootBranches' & (traverse . traverse) - (\(dp, bs) -> (dp,) <$> traverseBranches dp.target.anchor bs) + (\(dp, bs) -> (dp,) <$> traverseBranches dp.target.anchor (toNullable bs)) <&> map (map \(r, bas) -> (\(b, a) -> ((r, b), a)) <$> bas) <&> concatMap choices <&> mapMaybe (ensureSameAnchors . impureNonNull) <&> ordNub - <&> over (mapped . _1) (mapFromList . toNullable) + <&> over (mapped . _1) (impureNonNull . mapFromList . toNullable) + <&> over (mapped . _1 . mapped . _2) impureNonNull rootBranches'' & (traverse . _2) (\x -> traversePointlike False x target) <&> concatMap (\(rbs, ts) -> (rbs,) <$> ts) @@ -178,11 +179,11 @@ materializeNPath firstNid normalizedPath = do DPOutgoing transition -> traverseTransition nid (.outgoing) DPOutgoing transition DPIncoming transition -> traverseTransition nid (.incoming) DPIncoming transition DPSequence bs1 midpoint bs2 -> do - bs1's <- traverseBranches nid bs1 + bs1's <- traverseBranches nid (toNullable bs1) uptoMidpoints :: [(OSet (DPBranch NID), PointlikeDeterministicPath NID)] <- bs1's & (traverse . _2) (\x -> traversePointlike False x midpoint) <&> concatMap (\(bs1', ms) -> (bs1',) <$> ms) uptoMidpoints - & (traverse . _2) (\p -> (p,) <$> traverseBranches p.anchor bs2) - <&> concatMap (\(bs1', (p, bs2'ts)) -> first (DPSequence bs1' p) <$> bs2'ts) + & (traverse . _2) (\p -> (p,) <$> traverseBranches p.anchor (toNullable bs2)) + <&> concatMap (\(bs1', (p, bs2'ts)) -> first (DPSequence (impureNonNull bs1') p . impureNonNull) <$> bs2'ts) diff --git a/cli/src/Models/NormalizedPath.hs b/cli/src/Models/NormalizedPath.hs index 7a9fb7f0..c9009b1e 100644 --- a/cli/src/Models/NormalizedPath.hs +++ b/cli/src/Models/NormalizedPath.hs @@ -39,7 +39,12 @@ instance HasField "target" (DeterministicPath a) (PointlikeDeterministicPath a) -- at least two distinct roots (otherwise it should be Pointlike and the -- branches should go in a DPSequence in the branch set) data RootedDeterministicPath a = RootedDeterministicPath - { rootBranches :: OMap (DeterministicPath a) (OSet (DPBranch a)), + { rootBranches :: + NonNull + (OMap + (DeterministicPath a) + (NonNull (OSet (DPBranch a))) + ), target :: PointlikeDeterministicPath a } deriving stock (Eq, Ord, Show, Generic, Lift) @@ -91,9 +96,9 @@ data DPBranch a -- instead of -- @Sequence (Sequence (singleton a) m (singleton b)) n (singleton c)@) DPSequence - (OSet (DPBranch a)) + (NonNull (OSet (DPBranch a))) (PointlikeDeterministicPath a) - (OSet (DPBranch a)) + (NonNull (OSet (DPBranch a))) deriving stock (Eq, Ord, Show, Generic, Lift) deriving anyclass (NFData) @@ -120,8 +125,8 @@ pointify (branchify -> (roots, branches, target)) = do -- sequencing two Rooted paths. branchify :: RootedDeterministicPath Anchor -> - ( OSet (PointlikeDeterministicPath Anchor), - OSet (DPBranch Anchor), + ( NonNull (OSet (PointlikeDeterministicPath Anchor)), + NonNull (OSet (DPBranch Anchor)), PointlikeDeterministicPath Anchor ) branchify RootedDeterministicPath {..} = @@ -136,27 +141,27 @@ branchify RootedDeterministicPath {..} = pointlikes & unzip & bimap setFromList unions - in ( pointlikeRoots <> rootedRoots, - pointlikeBranches <> rootedBranches, + in ( impureNonNull $ pointlikeRoots <> rootedRoots, + impureNonNull $ pointlikeBranches <> rootedBranches, target ) where convertToBranches :: - ( ( OSet (PointlikeDeterministicPath Anchor), - OSet (DPBranch Anchor), + ( ( NonNull (OSet (PointlikeDeterministicPath Anchor)), + NonNull (OSet (DPBranch Anchor)), PointlikeDeterministicPath Anchor ), - OSet (DPBranch Anchor) + NonNull (OSet (DPBranch Anchor)) ) -> ( OSet (PointlikeDeterministicPath Anchor), - OSet (DPBranch Anchor) + NonNull (OSet (DPBranch Anchor)) ) convertToBranches ((w, x, y), z) = - (w, singletonSet $ smartBuildSequence x y z) + (toNullable w, impureNonNull $ singletonSet $ smartBuildSequence x y z) partitionRootedPointlike :: - [(DeterministicPath a, OSet (DPBranch a))] -> - ( [(RootedDeterministicPath a, OSet (DPBranch a))], - [(PointlikeDeterministicPath a, OSet (DPBranch a))] + [(DeterministicPath a, NonNull (OSet (DPBranch a)))] -> + ( [(RootedDeterministicPath a, NonNull (OSet (DPBranch a)))], + [(PointlikeDeterministicPath a, NonNull (OSet (DPBranch a)))] ) partitionRootedPointlike = partitionEithers . map \case @@ -212,45 +217,41 @@ mergePointlike p1 p2 = do smartBuildSequence :: (HasCallStack, Ord a) => - OSet (DPBranch a) -> + NonNull (OSet (DPBranch a)) -> PointlikeDeterministicPath a -> - OSet (DPBranch a) -> + NonNull (OSet (DPBranch a)) -> DPBranch a -smartBuildSequence as1 midpoint bs2 - | null as1 || null bs2 = - error "invariant broken: both branch sets must be nonempty" - | otherwise = case toList as1 of - [DPSequence leftBs leftMid leftRightBs] -> - DPSequence leftBs leftMid . singletonSet $ - smartBuildSequence leftRightBs midpoint bs2 - _ -> DPSequence as1 midpoint bs2 +smartBuildSequence as1 midpoint bs2 = case toList as1 of + [DPSequence leftBs leftMid leftRightBs] -> + DPSequence leftBs leftMid $ + impureNonNull $ singletonSet $ + smartBuildSequence leftRightBs midpoint bs2 + _ -> DPSequence as1 midpoint bs2 smartBuildRootedDeterministicPath :: (HasCallStack, Ord a) => - OMap (DeterministicPath a) (OSet (DPBranch a)) -> + NonNull (OMap (DeterministicPath a) (NonNull (OSet (DPBranch a)))) -> PointlikeDeterministicPath a -> RootedDeterministicPath a -smartBuildRootedDeterministicPath rootBranches target - | null rootBranches = - error "invariant broken: rootBranches must be nonempty" - | otherwise = case mapToList rootBranches of - [(r@(Rooted (RootedDeterministicPath (length -> 1) _)), b)] -> - smartBuildRootedDeterministicPath - (uncurry singletonMap (smartBuildRootBranch r b)) - target - _ -> RootedDeterministicPath rootBranches target +smartBuildRootedDeterministicPath rootBranches target = + case mapToList rootBranches of + [(r@(Rooted (RootedDeterministicPath (olength -> 1) _)), b)] -> + smartBuildRootedDeterministicPath + (impureNonNull $ uncurry singletonMap (smartBuildRootBranch r b)) + target + _ -> RootedDeterministicPath rootBranches target smartBuildRootBranch :: (HasCallStack, Ord a) => DeterministicPath a -> - OSet (DPBranch a) -> + NonNull (OSet (DPBranch a)) -> ( DeterministicPath a, - OSet (DPBranch a) + NonNull (OSet (DPBranch a)) ) smartBuildRootBranch (Rooted (RootedDeterministicPath (mapToList -> [(dp, branches)]) midpoint)) branchExtensions = - (dp, singletonSet $ smartBuildSequence branches midpoint branchExtensions) + (dp, impureNonNull $ singletonSet $ smartBuildSequence branches midpoint branchExtensions) smartBuildRootBranch dp branches = (dp, branches) sequenceDeterministicPaths :: @@ -266,7 +267,7 @@ sequenceDeterministicPaths Just $ Rooted $ smartBuildRootedDeterministicPath - (singletonMap (Pointlike newRoot) branches) + (impureNonNull $ singletonMap (Pointlike newRoot) branches) target sequenceDeterministicPaths (Rooted p1) (Pointlike p2) = do newTarget <- mergePointlike p1.target p2 @@ -277,7 +278,7 @@ sequenceDeterministicPaths midpoint <- foldlM1 mergePointlike (p1.target `ncons` toList roots) Just . Rooted $ smartBuildRootedDeterministicPath - (singletonMap (Rooted p1 {target = midpoint}) p2Branches) + (impureNonNull $ singletonMap (Rooted p1 {target = midpoint}) p2Branches) p2Target invertBranch :: (Ord a) => DPBranch a -> DPBranch a @@ -286,9 +287,9 @@ invertBranch = \case DPIncoming trans -> DPOutgoing trans DPSequence as1 midpoint bs2 -> DPSequence - (mapOSet invertBranch as1) + (impureNonNull $ mapOSet invertBranch as1) (invertPointlike midpoint) - (mapOSet invertBranch bs2) + (impureNonNull $ mapOSet invertBranch bs2) flipBranch :: (Ord a) => DPBranch a -> DPBranch a flipBranch = \case @@ -296,11 +297,10 @@ flipBranch = \case DPIncoming trans -> DPIncoming trans DPSequence as1 m12 bs23 -> case flipBranch <$> toList bs23 of - [] -> error "invariant broken: both branch sets must be nonempty" [DPSequence bs2 m23 bs3] -> smartBuildSequence bs3 (invertPointlike m23) $ - singletonSet (smartBuildSequence bs2 (invertPointlike m12) as1) - xs -> smartBuildSequence (setFromList xs) (invertPointlike m12) as1 + impureNonNull $ singletonSet (smartBuildSequence bs2 (invertPointlike m12) as1) + xs -> smartBuildSequence (impureNonNull $ setFromList xs) (invertPointlike m12) as1 backwardsCount :: DPBranch a -> Int backwardsCount = \case @@ -345,10 +345,10 @@ invertDeterministicPath (Pointlike p) = Just . Pointlike $ invertPointlike p invertDeterministicPath (Rooted (branchify -> (roots, branches, target))) = do newTarget <- foldlM1 mergePointlike =<< fromNullable (toList roots) - let newBranches = mapOSet invertBranch branches + let newBranches = impureNonNull $ mapOSet invertBranch branches Just . Rooted $ smartBuildRootedDeterministicPath - (singletonMap (Pointlike target) newBranches) + (impureNonNull $ singletonMap (Pointlike target) newBranches) newTarget normalizePath :: Path -> NormalizedPath Anchor @@ -365,17 +365,17 @@ normalizePath = \case Wild -> NormalizedPath . singletonSet . Rooted $ smartBuildRootedDeterministicPath - (singletonMap (Pointlike unanchored) (singletonSet (DPOutgoing DPWild))) + (impureNonNull $ singletonMap (Pointlike unanchored) (impureNonNull $ singletonSet (DPOutgoing DPWild))) unanchored Literal t -> NormalizedPath . singletonSet . Rooted $ smartBuildRootedDeterministicPath - (singletonMap (Pointlike unanchored) (singletonSet (DPOutgoing (DPLiteral t)))) + (impureNonNull $ singletonMap (Pointlike unanchored) (impureNonNull $ singletonSet (DPOutgoing (DPLiteral t)))) unanchored RegexMatch r -> NormalizedPath . singletonSet . Rooted $ smartBuildRootedDeterministicPath - (singletonMap (Pointlike unanchored) (singletonSet (DPOutgoing (DPRegex r)))) + (impureNonNull $ singletonMap (Pointlike unanchored) (impureNonNull $ singletonSet (DPOutgoing (DPRegex r)))) unanchored Backwards p -> let np = normalizePath p @@ -434,12 +434,12 @@ leastConstrainedNormalizedPath = & map (uncurry singletonMap) & unionsWith (<>) in smartBuildRootedDeterministicPath - newRootBranches + (impureNonNull newRootBranches) newTarget explodeUnanchored :: - (DeterministicPath Anchor, OSet (DPBranch Anchor)) -> - [(DeterministicPath FullyAnchored, OSet (DPBranch FullyAnchored))] + (DeterministicPath Anchor, NonNull (OSet (DPBranch Anchor))) -> + [(DeterministicPath FullyAnchored, NonNull (OSet (DPBranch FullyAnchored)))] explodeUnanchored = \case ( Rooted rdp@RootedDeterministicPath {target = PointlikeDeterministicPath {anchor = Unanchored}}, @@ -457,18 +457,18 @@ leastConstrainedNormalizedPath = ( \((root, b1), b2) -> smartBuildRootBranch root - ( singletonSet $ + ( impureNonNull $ singletonSet $ smartBuildSequence - (singletonSet b1) + (impureNonNull $ singletonSet b1) (PointlikeDeterministicPath (FJoinPoint mempty) mempty) - (singletonSet b2) + (impureNonNull $ singletonSet b2) ) ) (dp, bs) -> singleton $ smartBuildRootBranch (convertDeterministicPath dp) - (unions $ mapOSet convertBranch bs) + (impureNonNull $ unions $ mapOSet convertBranch bs) convertAnchor = \case Unanchored -> FJoinPoint mempty @@ -498,13 +498,13 @@ leastConstrainedNormalizedPath = mapOSet ( \(x, y) -> smartBuildSequence - (singletonSet x) + (impureNonNull $ singletonSet x) (convertPointlike joinPoint) - (singletonSet y) + (impureNonNull $ singletonSet y) ) (as1' `cartesianProductSet` bs2') | otherwise -> error "broken invariant: Unanchored path with loops" - _ -> singletonSet $ DPSequence as1' (convertPointlike midpoint) bs2' + _ -> singletonSet $ DPSequence (impureNonNull as1') (convertPointlike midpoint) (impureNonNull bs2') -- | Assign one JoinPoint to each Unanchored anchor leastNodesNormalizedPath :: @@ -535,15 +535,15 @@ traverseAnchors f (NormalizedPath paths) = convertRooted :: RootedDeterministicPath a -> f (RootedDeterministicPath b) convertRooted (RootedDeterministicPath rootBranches target) = - smartBuildRootedDeterministicPath . mapFromList + smartBuildRootedDeterministicPath . impureNonNull . mapFromList <$> traverse convertRootBranch (mapToList rootBranches) <*> convertPointlike target where - convertRootBranch :: (DeterministicPath a, OSet (DPBranch a)) -> f (DeterministicPath b, OSet (DPBranch b)) + convertRootBranch :: (DeterministicPath a, NonNull (OSet (DPBranch a))) -> f (DeterministicPath b, NonNull (OSet (DPBranch b))) convertRootBranch (dp, branches) = (,) <$> convertDeterministicPath dp - <*> (setFromList <$> traverse convertBranch (toList branches)) + <*> (impureNonNull . setFromList <$> traverse convertBranch (toList branches)) convertPointlike :: PointlikeDeterministicPath a -> f (PointlikeDeterministicPath b) convertPointlike (PointlikeDeterministicPath anchor loops) = @@ -556,7 +556,7 @@ traverseAnchors f (NormalizedPath paths) = DPOutgoing t -> pure $ DPOutgoing t DPIncoming t -> pure $ DPIncoming t DPSequence as1 midpoint as2 -> - smartBuildSequence . setFromList + smartBuildSequence . impureNonNull . setFromList <$> traverse convertBranch (toList as1) <*> convertPointlike midpoint - <*> (setFromList <$> traverse convertBranch (toList as2)) + <*> (impureNonNull . setFromList <$> traverse convertBranch (toList as2)) diff --git a/cli/src/Models/NormalizedPath/Parse.hs b/cli/src/Models/NormalizedPath/Parse.hs index f543ba47..9c7fee18 100644 --- a/cli/src/Models/NormalizedPath/Parse.hs +++ b/cli/src/Models/NormalizedPath/Parse.hs @@ -53,7 +53,7 @@ pPointlike pNID = label "pointlike" do -- | Parse rooted deterministic path: "[@target", "[branches]" pRootedPath :: Parser NID -> Parser (RootedDeterministicPath Anchor) pRootedPath pNID = label "rooted path" do - rootBranches <- brackets (pRootBranches pNID) + rootBranches <- impureNonNull <$> brackets (pRootBranches pNID) target <- option unanchored (pTarget pNID) pure $ RootedDeterministicPath rootBranches target @@ -63,8 +63,8 @@ pSequence pNID = label "sequence" do (initial, splitFirst -> ((m, b), rest)) <- pSequenceBranchSet pNID `via1` pMidpoint pure . uncurry ($) $ foldl' - (\(acc, x) (n, y) -> (acc . singletonSet . DPSequence x n, y)) - (DPSequence initial m :: OSet (DPBranch Anchor) -> DPBranch Anchor, b :: OSet (DPBranch Anchor)) + (\(acc, x) (n, y) -> (acc . impureNonNull . singletonSet . DPSequence (impureNonNull x) n, impureNonNull y)) + (DPSequence (impureNonNull initial) m :: NonNull (OSet (DPBranch Anchor)) -> DPBranch Anchor, impureNonNull b :: NonNull (OSet (DPBranch Anchor))) rest where pMidpoint = @@ -102,20 +102,20 @@ pExplicitAnchor pNID = -- | Parse root branches: "@ - Parser (OMap (DeterministicPath Anchor) (OSet (DPBranch Anchor))) + Parser (OMap (DeterministicPath Anchor) (NonNull (OSet (DPBranch Anchor)))) pRootBranches pNID = label "root branches" do branches <- sepBy1 (pRootBranch pNID) (symbol "&") pure $ unionsWith (<>) $ uncurry singletonMap <$> branches pRootBranch :: Parser NID -> - Parser (DeterministicPath Anchor, OSet (DPBranch Anchor)) + Parser (DeterministicPath Anchor, NonNull (OSet (DPBranch Anchor))) pRootBranch pNID = label "root branch" do root <- option (Pointlike unanchored) (pDeterministicPath pNID <* symbol "<") - branches <- pRootedBranchSet pNID + branches <- impureNonNull <$> pRootedBranchSet pNID pure (root, branches) pTarget :: Parser NID -> Parser (PointlikeDeterministicPath Anchor) From 4af04b7496971de9c513d359873922e4a76cacf7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 00:18:16 +0000 Subject: [PATCH 2/7] Replace impureNonNull with safer alternatives Added helper functions to MyPrelude.Collections: - traverseNonNull: safely traverse NonNull containers - mapOSetNN: map over NonNull OSets Replaced impureNonNull uses with safer alternatives: - Use singletonNNSet instead of impureNonNull . singletonSet - Use mapOSetNN instead of impureNonNull . mapOSet - Use traverseNonNull for traverse operations on NonNull - Use singletonNNMap for singleton maps This reduces the use of impureNonNull and makes the code safer by using functions specifically designed for NonNull types. --- cli/src/Graph/MaterializePath.hs | 2 +- cli/src/Models/NormalizedPath.hs | 51 +++++++++++++------------- cli/src/Models/NormalizedPath/Parse.hs | 6 ++- cli/src/MyPrelude/Collections.hs | 11 ++++++ 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/cli/src/Graph/MaterializePath.hs b/cli/src/Graph/MaterializePath.hs index 5d0b5683..f3cc6adc 100644 --- a/cli/src/Graph/MaterializePath.hs +++ b/cli/src/Graph/MaterializePath.hs @@ -186,4 +186,4 @@ materializeNPath firstNid normalizedPath = do <&> concatMap (\(bs1', ms) -> (bs1',) <$> ms) uptoMidpoints & (traverse . _2) (\p -> (p,) <$> traverseBranches p.anchor (toNullable bs2)) - <&> concatMap (\(bs1', (p, bs2'ts)) -> first (DPSequence (impureNonNull bs1') p . impureNonNull) <$> bs2'ts) + <&> concatMap (\(bs1', (p, bs2'ts)) -> first (\bs2' -> DPSequence (impureNonNull bs1') p (impureNonNull bs2')) <$> bs2'ts) diff --git a/cli/src/Models/NormalizedPath.hs b/cli/src/Models/NormalizedPath.hs index c9009b1e..67a1c333 100644 --- a/cli/src/Models/NormalizedPath.hs +++ b/cli/src/Models/NormalizedPath.hs @@ -157,7 +157,7 @@ branchify RootedDeterministicPath {..} = NonNull (OSet (DPBranch Anchor)) ) convertToBranches ((w, x, y), z) = - (toNullable w, impureNonNull $ singletonSet $ smartBuildSequence x y z) + (toNullable w, singletonNNSet $ smartBuildSequence x y z) partitionRootedPointlike :: [(DeterministicPath a, NonNull (OSet (DPBranch a)))] -> ( [(RootedDeterministicPath a, NonNull (OSet (DPBranch a)))], @@ -224,7 +224,7 @@ smartBuildSequence :: smartBuildSequence as1 midpoint bs2 = case toList as1 of [DPSequence leftBs leftMid leftRightBs] -> DPSequence leftBs leftMid $ - impureNonNull $ singletonSet $ + singletonNNSet $ smartBuildSequence leftRightBs midpoint bs2 _ -> DPSequence as1 midpoint bs2 @@ -236,9 +236,10 @@ smartBuildRootedDeterministicPath :: smartBuildRootedDeterministicPath rootBranches target = case mapToList rootBranches of [(r@(Rooted (RootedDeterministicPath (olength -> 1) _)), b)] -> - smartBuildRootedDeterministicPath - (impureNonNull $ uncurry singletonMap (smartBuildRootBranch r b)) - target + let (dp, branches) = smartBuildRootBranch r b + in smartBuildRootedDeterministicPath + (singletonNNMap dp branches) + target _ -> RootedDeterministicPath rootBranches target smartBuildRootBranch :: @@ -251,7 +252,7 @@ smartBuildRootBranch :: smartBuildRootBranch (Rooted (RootedDeterministicPath (mapToList -> [(dp, branches)]) midpoint)) branchExtensions = - (dp, impureNonNull $ singletonSet $ smartBuildSequence branches midpoint branchExtensions) + (dp, singletonNNSet $ smartBuildSequence branches midpoint branchExtensions) smartBuildRootBranch dp branches = (dp, branches) sequenceDeterministicPaths :: @@ -267,7 +268,7 @@ sequenceDeterministicPaths Just $ Rooted $ smartBuildRootedDeterministicPath - (impureNonNull $ singletonMap (Pointlike newRoot) branches) + (singletonNNMap (Pointlike newRoot) branches) target sequenceDeterministicPaths (Rooted p1) (Pointlike p2) = do newTarget <- mergePointlike p1.target p2 @@ -278,7 +279,7 @@ sequenceDeterministicPaths midpoint <- foldlM1 mergePointlike (p1.target `ncons` toList roots) Just . Rooted $ smartBuildRootedDeterministicPath - (impureNonNull $ singletonMap (Rooted p1 {target = midpoint}) p2Branches) + (singletonNNMap (Rooted p1 {target = midpoint}) p2Branches) p2Target invertBranch :: (Ord a) => DPBranch a -> DPBranch a @@ -287,9 +288,9 @@ invertBranch = \case DPIncoming trans -> DPOutgoing trans DPSequence as1 midpoint bs2 -> DPSequence - (impureNonNull $ mapOSet invertBranch as1) + (mapOSetNN invertBranch as1) (invertPointlike midpoint) - (impureNonNull $ mapOSet invertBranch bs2) + (mapOSetNN invertBranch bs2) flipBranch :: (Ord a) => DPBranch a -> DPBranch a flipBranch = \case @@ -299,7 +300,7 @@ flipBranch = \case case flipBranch <$> toList bs23 of [DPSequence bs2 m23 bs3] -> smartBuildSequence bs3 (invertPointlike m23) $ - impureNonNull $ singletonSet (smartBuildSequence bs2 (invertPointlike m12) as1) + singletonNNSet (smartBuildSequence bs2 (invertPointlike m12) as1) xs -> smartBuildSequence (impureNonNull $ setFromList xs) (invertPointlike m12) as1 backwardsCount :: DPBranch a -> Int @@ -345,10 +346,10 @@ invertDeterministicPath (Pointlike p) = Just . Pointlike $ invertPointlike p invertDeterministicPath (Rooted (branchify -> (roots, branches, target))) = do newTarget <- foldlM1 mergePointlike =<< fromNullable (toList roots) - let newBranches = impureNonNull $ mapOSet invertBranch branches + let newBranches = mapOSetNN invertBranch branches Just . Rooted $ smartBuildRootedDeterministicPath - (impureNonNull $ singletonMap (Pointlike target) newBranches) + (singletonNNMap (Pointlike target) newBranches) newTarget normalizePath :: Path -> NormalizedPath Anchor @@ -365,17 +366,17 @@ normalizePath = \case Wild -> NormalizedPath . singletonSet . Rooted $ smartBuildRootedDeterministicPath - (impureNonNull $ singletonMap (Pointlike unanchored) (impureNonNull $ singletonSet (DPOutgoing DPWild))) + (singletonNNMap (Pointlike unanchored) (singletonNNSet (DPOutgoing DPWild))) unanchored Literal t -> NormalizedPath . singletonSet . Rooted $ smartBuildRootedDeterministicPath - (impureNonNull $ singletonMap (Pointlike unanchored) (impureNonNull $ singletonSet (DPOutgoing (DPLiteral t)))) + (singletonNNMap (Pointlike unanchored) (singletonNNSet (DPOutgoing (DPLiteral t)))) unanchored RegexMatch r -> NormalizedPath . singletonSet . Rooted $ smartBuildRootedDeterministicPath - (impureNonNull $ singletonMap (Pointlike unanchored) (impureNonNull $ singletonSet (DPOutgoing (DPRegex r)))) + (singletonNNMap (Pointlike unanchored) (singletonNNSet (DPOutgoing (DPRegex r)))) unanchored Backwards p -> let np = normalizePath p @@ -457,11 +458,11 @@ leastConstrainedNormalizedPath = ( \((root, b1), b2) -> smartBuildRootBranch root - ( impureNonNull $ singletonSet $ + ( singletonNNSet $ smartBuildSequence - (impureNonNull $ singletonSet b1) + (singletonNNSet b1) (PointlikeDeterministicPath (FJoinPoint mempty) mempty) - (impureNonNull $ singletonSet b2) + (singletonNNSet b2) ) ) (dp, bs) -> @@ -498,9 +499,9 @@ leastConstrainedNormalizedPath = mapOSet ( \(x, y) -> smartBuildSequence - (impureNonNull $ singletonSet x) + (singletonNNSet x) (convertPointlike joinPoint) - (impureNonNull $ singletonSet y) + (singletonNNSet y) ) (as1' `cartesianProductSet` bs2') | otherwise -> error "broken invariant: Unanchored path with loops" @@ -543,7 +544,7 @@ traverseAnchors f (NormalizedPath paths) = convertRootBranch (dp, branches) = (,) <$> convertDeterministicPath dp - <*> (impureNonNull . setFromList <$> traverse convertBranch (toList branches)) + <*> traverseNonNull convertBranch branches convertPointlike :: PointlikeDeterministicPath a -> f (PointlikeDeterministicPath b) convertPointlike (PointlikeDeterministicPath anchor loops) = @@ -556,7 +557,7 @@ traverseAnchors f (NormalizedPath paths) = DPOutgoing t -> pure $ DPOutgoing t DPIncoming t -> pure $ DPIncoming t DPSequence as1 midpoint as2 -> - smartBuildSequence . impureNonNull . setFromList - <$> traverse convertBranch (toList as1) + smartBuildSequence + <$> traverseNonNull convertBranch as1 <*> convertPointlike midpoint - <*> (impureNonNull . setFromList <$> traverse convertBranch (toList as2)) + <*> traverseNonNull convertBranch as2 diff --git a/cli/src/Models/NormalizedPath/Parse.hs b/cli/src/Models/NormalizedPath/Parse.hs index 9c7fee18..331ff1fd 100644 --- a/cli/src/Models/NormalizedPath/Parse.hs +++ b/cli/src/Models/NormalizedPath/Parse.hs @@ -61,10 +61,12 @@ pRootedPath pNID = label "rooted path" do pSequence :: Parser NID -> Parser (DPBranch Anchor) pSequence pNID = label "sequence" do (initial, splitFirst -> ((m, b), rest)) <- pSequenceBranchSet pNID `via1` pMidpoint + let initialNN = impureNonNull initial + bNN = impureNonNull b pure . uncurry ($) $ foldl' - (\(acc, x) (n, y) -> (acc . impureNonNull . singletonSet . DPSequence (impureNonNull x) n, impureNonNull y)) - (DPSequence (impureNonNull initial) m :: NonNull (OSet (DPBranch Anchor)) -> DPBranch Anchor, impureNonNull b :: NonNull (OSet (DPBranch Anchor))) + (\(acc, x) (n, y) -> (acc . singletonNNSet . DPSequence x n, y)) + (DPSequence initialNN m :: NonNull (OSet (DPBranch Anchor)) -> DPBranch Anchor, bNN :: NonNull (OSet (DPBranch Anchor))) rest where pMidpoint = diff --git a/cli/src/MyPrelude/Collections.hs b/cli/src/MyPrelude/Collections.hs index ccbed21d..acc970ed 100644 --- a/cli/src/MyPrelude/Collections.hs +++ b/cli/src/MyPrelude/Collections.hs @@ -125,6 +125,9 @@ mapSet = Set.map mapOSet :: (Ord b) => (a -> b) -> OSet a -> OSet b mapOSet f = setFromList . map f . toList +mapOSetNN :: (HasCallStack, Ord b) => (a -> b) -> NonNull (OSet a) -> NonNull (OSet b) +mapOSetNN f = impureNonNull . mapOSet f . toNullable + mapFromSet :: (Ord k) => Set k -> Map k () mapFromSet = Map.fromSet (const ()) @@ -287,3 +290,11 @@ ixsetmapped = iso IxSet.toSet IxSet.fromSet . setmapped nnmap :: (HasCallStack, MonoFoldable (f b), Functor f) => (a -> b) -> NonNull (f a) -> NonNull (f b) nnmap f = impureNonNull . fmap f . toNullable + +traverseNonNull :: + (HasCallStack, MonoFoldable (g b), Traversable f, Applicative g) => + (a -> g b) -> + NonNull (f a) -> + g (NonNull (f b)) +traverseNonNull f = fmap impureNonNull . traverse f . toNullable + From f7146762489a225acc0fdeff7c346aa80cb0811c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 00:19:06 +0000 Subject: [PATCH 3/7] Implement traverseNonNull without impureNonNull Use pattern matching and ncons to build the NonNull result directly, avoiding the need for impureNonNull. The error case remains but is marked as impossible since NonNull values should never be empty. --- cli/src/MyPrelude/Collections.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/src/MyPrelude/Collections.hs b/cli/src/MyPrelude/Collections.hs index acc970ed..404762be 100644 --- a/cli/src/MyPrelude/Collections.hs +++ b/cli/src/MyPrelude/Collections.hs @@ -296,5 +296,7 @@ traverseNonNull :: (a -> g b) -> NonNull (f a) -> g (NonNull (f b)) -traverseNonNull f = fmap impureNonNull . traverse f . toNullable +traverseNonNull f xs = case toList (toNullable xs) of + [] -> error "traverseNonNull: impossible - NonNull is empty" + (y : ys) -> ncons <$> f y <*> traverse f ys From f6011d96269596b3260b6ba789cf87be8c32311a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 00:24:19 +0000 Subject: [PATCH 4/7] Revert traverseNonNull to use impureNonNull The original implementation is simpler and more elegant. The use of impureNonNull is justified here because traversing a non-empty structure always produces a non-empty result. --- cli/src/MyPrelude/Collections.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/src/MyPrelude/Collections.hs b/cli/src/MyPrelude/Collections.hs index 404762be..acc970ed 100644 --- a/cli/src/MyPrelude/Collections.hs +++ b/cli/src/MyPrelude/Collections.hs @@ -296,7 +296,5 @@ traverseNonNull :: (a -> g b) -> NonNull (f a) -> g (NonNull (f b)) -traverseNonNull f xs = case toList (toNullable xs) of - [] -> error "traverseNonNull: impossible - NonNull is empty" - (y : ys) -> ncons <$> f y <*> traverse f ys +traverseNonNull f = fmap impureNonNull . traverse f . toNullable From 1a40771e84eb39722a44f68395c0f6478c694515 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 01:30:02 +0000 Subject: [PATCH 5/7] Fix traverseNonNull type signature and remove Lift/NFData instances - Fixed traverseNonNull to require MonoFoldable (f b) instead of (g b) - Removed Lift and NFData deriving instances from types using NonNull (RootedDeterministicPath, DPBranch, DeterministicPath, PointlikeDeterministicPath, NormalizedPath) - NonNull types don't have Lift or NFData instances, so can't be derived automatically Remaining work: Fix type mismatches where NonNull values need toNullable conversions --- cli/src/Models/NormalizedPath.hs | 15 +++++---------- cli/src/MyPrelude/Collections.hs | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/cli/src/Models/NormalizedPath.hs b/cli/src/Models/NormalizedPath.hs index 67a1c333..e457f505 100644 --- a/cli/src/Models/NormalizedPath.hs +++ b/cli/src/Models/NormalizedPath.hs @@ -24,8 +24,7 @@ data FullyAnchored data DeterministicPath a = Rooted (RootedDeterministicPath a) | Pointlike (PointlikeDeterministicPath a) - deriving stock (Eq, Ord, Show, Generic, Lift) - deriving anyclass (NFData) + deriving stock (Eq, Ord, Show, Generic) instance HasField "target" (DeterministicPath a) (PointlikeDeterministicPath a) where getField (Rooted p) = p.target @@ -47,8 +46,7 @@ data RootedDeterministicPath a = RootedDeterministicPath ), target :: PointlikeDeterministicPath a } - deriving stock (Eq, Ord, Show, Generic, Lift) - deriving anyclass (NFData) + deriving stock (Eq, Ord, Show, Generic) -- | A pointlike deterministic path. This is a path that has a single Root -- and the target is the same as the Root. @@ -59,8 +57,7 @@ data PointlikeDeterministicPath a -- | each of these can also be inverted, see `invertLoop` for details loops :: OSet (DPBranch a) } - deriving stock (Eq, Ord, Show, Generic, Lift) - deriving anyclass (NFData) + deriving stock (Eq, Ord, Show, Generic) unanchored :: PointlikeDeterministicPath Anchor unanchored = PointlikeDeterministicPath Unanchored mempty @@ -99,12 +96,10 @@ data DPBranch a (NonNull (OSet (DPBranch a))) (PointlikeDeterministicPath a) (NonNull (OSet (DPBranch a))) - deriving stock (Eq, Ord, Show, Generic, Lift) - deriving anyclass (NFData) + deriving stock (Eq, Ord, Show, Generic) newtype NormalizedPath a = NormalizedPath {union :: Set (DeterministicPath a)} - deriving stock (Eq, Ord, Show, Generic, Lift) - deriving anyclass (NFData) + deriving stock (Eq, Ord, Show, Generic) pointify :: RootedDeterministicPath Anchor -> diff --git a/cli/src/MyPrelude/Collections.hs b/cli/src/MyPrelude/Collections.hs index acc970ed..5106d4fb 100644 --- a/cli/src/MyPrelude/Collections.hs +++ b/cli/src/MyPrelude/Collections.hs @@ -292,7 +292,7 @@ nnmap :: (HasCallStack, MonoFoldable (f b), Functor f) => (a -> b) -> NonNull (f nnmap f = impureNonNull . fmap f . toNullable traverseNonNull :: - (HasCallStack, MonoFoldable (g b), Traversable f, Applicative g) => + (HasCallStack, MonoFoldable (f b), Traversable f, Applicative g) => (a -> g b) -> NonNull (f a) -> g (NonNull (f b)) From 72759dae1b04c8a8e83045ab139c568c9b23bd62 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 02:21:08 +0000 Subject: [PATCH 6/7] Add toNullable conversions for NonNull type usage - Added toNullable() calls when passing NonNull values to functions expecting regular containers - Fixed mapToList usage on NonNull OMaps by adding toNullable before mapToList - Updated unionWith to work with NonNull OMaps using toNullable/impureNonNull - Converted traverse operations on NonNull OSets to use toList/setFromList pattern - Updated parsers to return NonNull types (pSequenceBranchSet, pRootedBranchSet) - Fixed test specs to use singletonNNMap and singletonNNSet --- cli/src/Models/NormalizedPath.hs | 32 ++++++++++++---------- cli/src/Models/NormalizedPath/Parse.hs | 18 ++++++------ cli/src/Models/NormalizedPath/ParseSpec.hs | 4 +-- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/cli/src/Models/NormalizedPath.hs b/cli/src/Models/NormalizedPath.hs index e457f505..decc9b73 100644 --- a/cli/src/Models/NormalizedPath.hs +++ b/cli/src/Models/NormalizedPath.hs @@ -108,7 +108,7 @@ pointify (branchify -> (roots, branches, target)) = do protoPoint <- foldlM1 mergePointlike (target `ncons` toList roots) Just protoPoint - { loops = protoPoint.loops <> branches, + { loops = protoPoint.loops <> toNullable branches, anchor = fromJustEx $ mergeAnchor (JoinPoint mempty) protoPoint.anchor } @@ -125,17 +125,17 @@ branchify :: PointlikeDeterministicPath Anchor ) branchify RootedDeterministicPath {..} = - let (rooteds, pointlikes) = partitionRootedPointlike (mapToList rootBranches) + let (rooteds, pointlikes) = partitionRootedPointlike (mapToList (toNullable rootBranches)) (rootedRoots, rootedBranches) = rooteds & over (mapped . _1) branchify & map convertToBranches & unzip - & bimap unions unions + & bimap unions (unions . map toNullable) (pointlikeRoots, pointlikeBranches) = pointlikes & unzip - & bimap setFromList unions + & bimap setFromList (unions . map toNullable) in ( impureNonNull $ pointlikeRoots <> rootedRoots, impureNonNull $ pointlikeBranches <> rootedBranches, target @@ -169,7 +169,7 @@ intersectDeterministicPaths :: Maybe (DeterministicPath Anchor) intersectDeterministicPaths (Rooted p1) (Rooted p2) = do newTarget <- mergePointlike p1.target p2.target - let newSourceBranches = unionWith (<>) p1.rootBranches p2.rootBranches + let newSourceBranches = impureNonNull $ unionWith (<>) (toNullable p1.rootBranches) (toNullable p2.rootBranches) Just . Rooted $ smartBuildRootedDeterministicPath newSourceBranches newTarget intersectDeterministicPaths (Pointlike p1) (Pointlike p2) = do Pointlike <$> mergePointlike p1 p2 @@ -229,7 +229,7 @@ smartBuildRootedDeterministicPath :: PointlikeDeterministicPath a -> RootedDeterministicPath a smartBuildRootedDeterministicPath rootBranches target = - case mapToList rootBranches of + case mapToList (toNullable rootBranches) of [(r@(Rooted (RootedDeterministicPath (olength -> 1) _)), b)] -> let (dp, branches) = smartBuildRootBranch r b in smartBuildRootedDeterministicPath @@ -245,7 +245,7 @@ smartBuildRootBranch :: NonNull (OSet (DPBranch a)) ) smartBuildRootBranch - (Rooted (RootedDeterministicPath (mapToList -> [(dp, branches)]) midpoint)) + (Rooted (RootedDeterministicPath (mapToList . toNullable -> [(dp, branches)]) midpoint)) branchExtensions = (dp, singletonNNSet $ smartBuildSequence branches midpoint branchExtensions) smartBuildRootBranch dp branches = (dp, branches) @@ -425,6 +425,7 @@ leastConstrainedNormalizedPath = let newTarget = convertPointlike target newRootBranches = rootBranches + & toNullable & mapToList & concatMap explodeUnanchored & map (uncurry singletonMap) @@ -444,10 +445,11 @@ leastConstrainedNormalizedPath = let RootedDeterministicPath {..} = convertRooted rdp rootBranches' :: [(DeterministicPath FullyAnchored, DPBranch FullyAnchored)] = rootBranches + & toNullable & mapToList & over (mapped . _2) toList & concatMap (\(root, bs) -> map (root,) bs) - branchExtensions' :: OSet (DPBranch FullyAnchored) = unions (mapOSet convertBranch branchExtensions) + branchExtensions' :: OSet (DPBranch FullyAnchored) = unions (mapOSet convertBranch (toNullable branchExtensions)) in (rootBranches' `cartesianProduct` toList branchExtensions') & map ( \((root, b1), b2) -> @@ -464,7 +466,7 @@ leastConstrainedNormalizedPath = singleton $ smartBuildRootBranch (convertDeterministicPath dp) - (impureNonNull $ unions $ mapOSet convertBranch bs) + (impureNonNull $ unions $ mapOSet convertBranch (toNullable bs)) convertAnchor = \case Unanchored -> FJoinPoint mempty @@ -486,8 +488,8 @@ leastConstrainedNormalizedPath = DPOutgoing t -> singletonSet $ DPOutgoing t DPIncoming t -> singletonSet $ DPIncoming t DPSequence as1 midpoint bs2 -> do - let as1' = unions (mapOSet convertBranch as1) - let bs2' = unions (mapOSet convertBranch bs2) + let as1' = unions (mapOSet convertBranch (toNullable as1)) + let bs2' = unions (mapOSet convertBranch (toNullable bs2)) case midpoint.anchor of Unanchored | null midpoint.loops -> @@ -532,14 +534,14 @@ traverseAnchors f (NormalizedPath paths) = convertRooted :: RootedDeterministicPath a -> f (RootedDeterministicPath b) convertRooted (RootedDeterministicPath rootBranches target) = smartBuildRootedDeterministicPath . impureNonNull . mapFromList - <$> traverse convertRootBranch (mapToList rootBranches) + <$> traverse convertRootBranch (mapToList (toNullable rootBranches)) <*> convertPointlike target where convertRootBranch :: (DeterministicPath a, NonNull (OSet (DPBranch a))) -> f (DeterministicPath b, NonNull (OSet (DPBranch b))) convertRootBranch (dp, branches) = (,) <$> convertDeterministicPath dp - <*> traverseNonNull convertBranch branches + <*> (impureNonNull . setFromList <$> traverse convertBranch (toList branches)) convertPointlike :: PointlikeDeterministicPath a -> f (PointlikeDeterministicPath b) convertPointlike (PointlikeDeterministicPath anchor loops) = @@ -553,6 +555,6 @@ traverseAnchors f (NormalizedPath paths) = DPIncoming t -> pure $ DPIncoming t DPSequence as1 midpoint as2 -> smartBuildSequence - <$> traverseNonNull convertBranch as1 + <$> (impureNonNull . setFromList <$> traverse convertBranch (toList as1)) <*> convertPointlike midpoint - <*> traverseNonNull convertBranch as2 + <*> (impureNonNull . setFromList <$> traverse convertBranch (toList as2)) diff --git a/cli/src/Models/NormalizedPath/Parse.hs b/cli/src/Models/NormalizedPath/Parse.hs index 331ff1fd..54456e52 100644 --- a/cli/src/Models/NormalizedPath/Parse.hs +++ b/cli/src/Models/NormalizedPath/Parse.hs @@ -61,32 +61,30 @@ pRootedPath pNID = label "rooted path" do pSequence :: Parser NID -> Parser (DPBranch Anchor) pSequence pNID = label "sequence" do (initial, splitFirst -> ((m, b), rest)) <- pSequenceBranchSet pNID `via1` pMidpoint - let initialNN = impureNonNull initial - bNN = impureNonNull b pure . uncurry ($) $ foldl' (\(acc, x) (n, y) -> (acc . singletonNNSet . DPSequence x n, y)) - (DPSequence initialNN m :: NonNull (OSet (DPBranch Anchor)) -> DPBranch Anchor, bNN :: NonNull (OSet (DPBranch Anchor))) + (DPSequence initial m :: NonNull (OSet (DPBranch Anchor)) -> DPBranch Anchor, b :: NonNull (OSet (DPBranch Anchor))) rest where pMidpoint = symbol "/" *> option unanchored (pPointlike pNID) <* symbol "|" -- | Parse a set of branches separated by & -pSequenceBranchSet :: Parser NID -> Parser (OSet (DPBranch Anchor)) +pSequenceBranchSet :: Parser NID -> Parser (NonNull (OSet (DPBranch Anchor))) pSequenceBranchSet pNID = label "sequence branch set" $ - try (setFromList <$> pMultiple) - <|> (singletonSet <$> pSingleBranch) + try (impureNonNull . setFromList <$> pMultiple) + <|> (singletonNNSet <$> pSingleBranch) where pMultiple = parens (pBranch pNID `sepBy1` symbol "&") -- | Parse a set of branches separated by & -pRootedBranchSet :: Parser NID -> Parser (OSet (DPBranch Anchor)) +pRootedBranchSet :: Parser NID -> Parser (NonNull (OSet (DPBranch Anchor))) pRootedBranchSet pNID = label "rooted branch set" $ - try (singletonSet <$> pBranch pNID) - <|> (setFromList <$> pMultiple) + try (singletonNNSet <$> pBranch pNID) + <|> (impureNonNull . setFromList <$> pMultiple) where pMultiple = parens (pBranch pNID `sepBy1` symbol "&") @@ -117,7 +115,7 @@ pRootBranch pNID = label "root branch" do option (Pointlike unanchored) (pDeterministicPath pNID <* symbol "<") - branches <- impureNonNull <$> pRootedBranchSet pNID + branches <- pRootedBranchSet pNID pure (root, branches) pTarget :: Parser NID -> Parser (PointlikeDeterministicPath Anchor) diff --git a/cli/src/Models/NormalizedPath/ParseSpec.hs b/cli/src/Models/NormalizedPath/ParseSpec.hs index 9c1dcc05..5133049a 100644 --- a/cli/src/Models/NormalizedPath/ParseSpec.hs +++ b/cli/src/Models/NormalizedPath/ParseSpec.hs @@ -135,13 +135,13 @@ singletonBranch :: DPBranch Anchor -> NormalizedPath Anchor singletonBranch branch = NormalizedPath . singletonSet . Rooted $ RootedDeterministicPath - (singletonMap (Pointlike unanchored) (singletonSet branch)) + (singletonNNMap (Pointlike unanchored) (singletonNNSet branch)) unanchored branches :: [DPBranch Anchor] -> NormalizedPath Anchor branches bs = NormalizedPath . setFromList $ - [ Rooted (RootedDeterministicPath (singletonMap (Pointlike unanchored) (singletonSet b)) unanchored) + [ Rooted (RootedDeterministicPath (singletonNNMap (Pointlike unanchored) (singletonNNSet b)) unanchored) | b <- bs ] From a3a6864429e1151ab32117c336d71825d15a8e16 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 02:24:44 +0000 Subject: [PATCH 7/7] Fix ParseSpec test to use NonNull types - Updated one test case to use impureNonNull and singletonNNSet Note: Many test cases in ParseSpec still need updates to use impureNonNull . setFromList for DPSequence arguments. This is because DPSequence now takes NonNull (OSet (DPBranch a)) instead of OSet (DPBranch a). Additionally, TH file needs Lift instances which were removed. --- cli/src/Models/NormalizedPath/ParseSpec.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/src/Models/NormalizedPath/ParseSpec.hs b/cli/src/Models/NormalizedPath/ParseSpec.hs index 5133049a..1a8e7cf8 100644 --- a/cli/src/Models/NormalizedPath/ParseSpec.hs +++ b/cli/src/Models/NormalizedPath/ParseSpec.hs @@ -45,10 +45,10 @@ test_pNormalizedPath = "[@@" `parsesTo` singletonRooted ( RootedDeterministicPath - ( mapFromList - [ (Pointlike joinPoint, singletonSet (DPOutgoing (DPLiteral "a"))), - (Pointlike $ specific (smallNID 1), singletonSet (DPOutgoing (DPLiteral "b"))), - (Pointlike unanchored, singletonSet (DPOutgoing (DPLiteral "c"))) + ( impureNonNull $ mapFromList + [ (Pointlike joinPoint, singletonNNSet (DPOutgoing (DPLiteral "a"))), + (Pointlike $ specific (smallNID 1), singletonNNSet (DPOutgoing (DPLiteral "b"))), + (Pointlike unanchored, singletonNNSet (DPOutgoing (DPLiteral "c"))) ] ) joinPoint