diff --git a/data/hlint.yaml b/data/hlint.yaml index f007f2b2..ca08cd2c 100644 --- a/data/hlint.yaml +++ b/data/hlint.yaml @@ -1476,6 +1476,35 @@ - warn: {lhs: foldr' f c (reverse x), rhs: foldl' (flip f) c x, name: Use left fold instead of right fold} - warn: {lhs: foldl' f c (reverse x), rhs: foldr (flip f) c x, note: IncreasesLaziness, name: Use right fold instead of left fold} +- group: + name: performance + enabled: false + rules: + + # Text / ByteString strict left folds. The lazy `foldl` over these + # bulk-data types builds a thunk chain proportional to the element + # count, which blows the stack on realistic inputs. `foldl'` is a + # drop-in, same-module replacement whenever the accumulator is + # strict-amenable (which it almost always is for numeric counters, + # Builders, strict Maps, etc.). Match fully-qualified names only so + # the rule does not fire on the unrelated Foldable-polymorphic + # `foldl` from Prelude/Data.Foldable. + - warn: {lhs: Data.Text.foldl f z t, rhs: Data.Text.foldl' f z t, name: "Use foldl'"} + - warn: {lhs: Data.Text.Lazy.foldl f z t, rhs: Data.Text.Lazy.foldl' f z t, name: "Use foldl'"} + - warn: {lhs: Data.ByteString.foldl f z b, rhs: Data.ByteString.foldl' f z b, name: "Use foldl'"} + - warn: {lhs: Data.ByteString.Lazy.foldl f z b, rhs: Data.ByteString.Lazy.foldl' f z b, name: "Use foldl'"} + - warn: {lhs: Data.ByteString.Char8.foldl f z b, rhs: Data.ByteString.Char8.foldl' f z b, name: "Use foldl'"} + - warn: {lhs: Data.ByteString.Lazy.Char8.foldl f z b, rhs: Data.ByteString.Lazy.Char8.foldl' f z b, name: "Use foldl'"} + + # Text concat-of-map fuses into concatMap, avoiding the intermediate + # [Text] spine and its associated allocation. Semantics-preserving: + # `Data.Text.concatMap f = Data.Text.concat . map f` by construction. + # Not applied to ByteString: `Data.ByteString.concatMap` has type + # (Word8 -> ByteString) -> ByteString -> ByteString, so it is NOT + # the fusion of `concat . map` over `[ByteString]`. + - warn: {lhs: Data.Text.concat (map f xs), rhs: Data.Text.concatMap f xs, name: "Use Data.Text.concatMap"} + - warn: {lhs: Data.Text.Lazy.concat (map f xs), rhs: Data.Text.Lazy.concatMap f xs, name: "Use Data.Text.Lazy.concatMap"} + - group: # used for tests, enabled when testing this file name: testing diff --git a/tests/flag-with-group-performance-text-bs.test b/tests/flag-with-group-performance-text-bs.test new file mode 100644 index 00000000..a37ac3ef --- /dev/null +++ b/tests/flag-with-group-performance-text-bs.test @@ -0,0 +1,68 @@ +--------------------------------------------------------------------- +FILE tests/flag-with-group-performance-text-bs.hs +import qualified Data.Text as T +import qualified Data.Text.Lazy as TL +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Char8 as BSC +import qualified Data.ByteString.Lazy.Char8 as BLC +ft f z t = print (T.foldl f z t) +ftl f z t = print (TL.foldl f z t) +fbs f z b = print (BS.foldl f z b) +fbl f z b = print (BL.foldl f z b) +fbsc f z b = print (BSC.foldl f z b) +fblc f z b = print (BLC.foldl f z b) +ct f xs = print (T.concat (map f xs)) +ctl f xs = print (TL.concat (map f xs)) +RUN "--with-group=performance" tests/flag-with-group-performance-text-bs.hs +OUTPUT +tests/flag-with-group-performance-text-bs.hs:7:19-31: Warning: Use foldl' +Found: + T.foldl f z t +Perhaps: + T.foldl' f z t + +tests/flag-with-group-performance-text-bs.hs:8:20-33: Warning: Use foldl' +Found: + TL.foldl f z t +Perhaps: + TL.foldl' f z t + +tests/flag-with-group-performance-text-bs.hs:9:20-33: Warning: Use foldl' +Found: + BS.foldl f z b +Perhaps: + BS.foldl' f z b + +tests/flag-with-group-performance-text-bs.hs:10:20-33: Warning: Use foldl' +Found: + BL.foldl f z b +Perhaps: + BL.foldl' f z b + +tests/flag-with-group-performance-text-bs.hs:11:21-35: Warning: Use foldl' +Found: + BSC.foldl f z b +Perhaps: + BSC.foldl' f z b + +tests/flag-with-group-performance-text-bs.hs:12:21-35: Warning: Use foldl' +Found: + BLC.foldl f z b +Perhaps: + BLC.foldl' f z b + +tests/flag-with-group-performance-text-bs.hs:13:18-36: Warning: Use Data.Text.concatMap +Found: + T.concat (map f xs) +Perhaps: + T.concatMap f xs + +tests/flag-with-group-performance-text-bs.hs:14:19-38: Warning: Use Data.Text.Lazy.concatMap +Found: + TL.concat (map f xs) +Perhaps: + TL.concatMap f xs + +8 hints +