packages feed

opt-env-conf 0.15.0.1 → 0.15.0.2

raw patch · 4 files changed

+30/−17 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,15 @@ # Changelog +## [0.15.0.2] - 2026-05-15++### Changed++* Fixed an exponential-time blowup when parsing inputs with several `many`-style+  options combined with a `choice` containing positional arguments. Parses that+  previously took minutes now complete in milliseconds. The fix makes the+  internal `ListT` nondet stream lazy in its second argument and threads inner+  branches into the outer parser on demand.+ ## [0.15.0.1] - 2026-03-18  ### Changed
opt-env-conf.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           opt-env-conf-version:        0.15.0.1+version:        0.15.0.2 synopsis:       Settings parsing for Haskell: command-line arguments, environment variables, and configuration values. homepage:       https://github.com/NorfairKing/opt-env-conf#readme bug-reports:    https://github.com/NorfairKing/opt-env-conf/issues
src/OptEnvConf/NonDet.hs view
@@ -56,12 +56,16 @@ joinMMMList :: (Monad m) => m (MList m (m (MList m a))) -> m (MList m a) joinMMMList = (>>= joinMMList) -appendMList :: (Functor m) => MList m a -> MList m a -> MList m a-appendMList MNil ml = ml-appendMList (MCons a ml1) ml2 = MCons a $ (`appendMList` ml2) <$> ml1--appendMMMList :: (Applicative m) => m (MList m a) -> m (MList m a) -> m (MList m a)-appendMMMList ml1 ml2 = appendMList <$> ml1 <*> ml2+-- Lazy in the second argument: do not run its effects until the first list+-- is exhausted. A strict definition (e.g. liftA2 over an eager concat) forces+-- the entire downstream search tree just to produce the head element, which+-- causes exponential blowup through ListT's >>= and <|>.+appendMMMList :: (Monad m) => m (MList m a) -> m (MList m a) -> m (MList m a)+appendMMMList ml1 ml2 = do+  l1 <- ml1+  case l1 of+    MNil -> ml2+    MCons a m -> pure $ MCons a (appendMMMList m ml2)  -- This can be directly used as a monad transformer newtype ListT m a = ListT {unListT :: m (MList m a)}
src/OptEnvConf/Run.hs view
@@ -152,8 +152,7 @@         ppIndent $ do           e <- ask           s <- get-          results <- liftIO $ runPP (go p') s e-          (result, s') <- ppNonDetList results+          (result, s') <- ppNonDet $ runPPNonDet (go p') s e           put s'           case result of             Success a -> pure a@@ -606,13 +605,15 @@       MonadState PPState     ) -runPP ::+-- Keeps nondeterminism lazy: callers consume the resulting branches one at a+-- time, so unreached branches never run.+runPPNonDet ::   PP a ->   PPState ->   PPEnv ->-  IO [(Validation ParseError a, PPState)]-runPP (PP p) args envVars =-  runNonDetT (runStateT (runValidationT (runReaderT p envVars)) args)+  NonDetT IO (Validation ParseError a, PPState)+runPPNonDet (PP p) args envVars =+  runStateT (runValidationT (runReaderT p envVars)) args  runPPLazy ::   PP a ->@@ -631,13 +632,11 @@ tryPP pp = do   s <- get   e <- ask-  results <- liftIO $ runPP pp s e-  (errOrRes, s') <- ppNonDetList results+  (errOrRes, s') <- ppNonDet $ runPPNonDet pp s e   case errOrRes of     Failure errs ->       if all errorIsForgivable errs-        then do-          pure Nothing+        then pure Nothing         else ppErrors' errs     Success a -> do       put s' -- Only set state if parsing succeeded.