Improve Distribution.Lex.tokenizeQuotedWords - #12187
Open
Bodigrim wants to merge 1 commit into
Open
Conversation
Bodigrim
force-pushed
the
faster-tokenizeQuotedWords
branch
from
July 30, 2026 21:37
572d642 to
8b57558
Compare
Bodigrim
force-pushed
the
faster-tokenizeQuotedWords
branch
from
August 4, 2026 22:16
8b57558 to
2d0257a
Compare
ulysses4ever
reviewed
Aug 5, 2026
| repack :: NonEmpty String -> [String] | ||
| repack (zs :| acc) = if null zs then acc else zs : acc | ||
|
|
||
| alg :: Char -> (Bool -> NonEmpty String) -> Bool -> NonEmpty String |
Collaborator
There was a problem hiding this comment.
the previous version had nice haddocks on parameters of go, which helped a lot with understanding this code. Could you please follow that lead?
The new version is more concise, 25% faster and allocates 50% less.
(The reason of my interest to this function is that I'm investigating
whether any usages of `DList` throughout Cabal code are up to the purpose
and not slowing things down)
Tested and benchmarked using the following program:
```haskell
{- cabal:
build-depends: base, dlist, tasty, tasty-quickcheck, tasty-bench
-}
{-# LANGUAGE LambdaCase #-}
import Data.Char (isSpace)
import Data.DList (DList(..), toList, singleton)
import Data.List (replicate)
import Data.List.NonEmpty (NonEmpty(..))
import Test.Tasty.Bench (defaultMain, bench, nf)
import Test.Tasty.QuickCheck
tokenizeQuotedWords :: String -> [String]
tokenizeQuotedWords = filter (not . null) . go False mempty
where
go
:: Bool
-- \^ in quoted region
-> DList Char
-- \^ accumulator
-> String
-- \^ string to be parsed
-> [String]
-- \^ parse result
go _ accum []
| [] <- accum' = []
| otherwise = [accum']
where
accum' = toList accum
go False accum (c : cs)
| isSpace c = toList accum : go False mempty cs
| c == '"' = go True accum cs
go True accum (c : cs)
| c == '"' = go False accum cs
go quoted accum (c : cs) =
go quoted (accum <> singleton c) cs
tokenizeQuotedWords2 :: String -> [String]
tokenizeQuotedWords2 xs = repack $ foldr alg (const ([] :| [])) xs False
where
repack :: NonEmpty String -> [String]
repack (zs :| acc) = if null zs then acc else zs : acc
alg :: Char -> (Bool -> NonEmpty String) -> Bool -> NonEmpty String
alg '"' rest mode = rest (not mode)
alg c rest False
| isSpace c = [] :| repack (rest False)
alg c rest mode = case rest mode of
w :| ws -> (c : w) :| ws
data Foo = Space | Quote | CharA | CharB
deriving (Eq, Ord, Show, Bounded, Enum)
instance Arbitrary Foo where
arbitrary = arbitraryBoundedEnum
fooToChar :: Foo -> Char
fooToChar = \case
Space -> ' '
Quote -> '"'
CharA -> 'a'
CharB -> 'b'
main :: IO ()
main = defaultMain
[ testProperty "same results" $
\xs -> let ys = map fooToChar xs in tokenizeQuotedWords ys === tokenizeQuotedWords2 ys
, bench "old" $ nf tokenizeQuotedWords benchString
, bench "new" $ nf tokenizeQuotedWords2 benchString
]
benchString :: String
benchString = concat $ replicate 10 "foo \"bar baz\" quux"
```
Bodigrim
force-pushed
the
faster-tokenizeQuotedWords
branch
from
August 5, 2026 19:12
2d0257a to
e81baa7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The new version is more concise, 25% faster and allocates 50% less.
(The reason of my interest to this function is that I'm investigating whether any usages of
DListthroughout Cabal code are up to the purpose and not slowing things down)Tested and benchmarked using the following program:
Template B: This PR does not modify behaviour or interface
Include the following checklist in your PR: