Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions data/hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,34 @@
- 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
imports:
- package base
rules:

# Lazy-list O(n) spine-forcing anti-patterns. On a lazy list, walking
# the full cons spine just to compute a cheaper property (or build
# an intermediate list we then discard) is wasteful and fails to
# terminate on infinite inputs. The `length x == 0 / > 0 / <= 0 / ...`
# family is already covered in the default group; the rules below
# cover the remaining list-spine anti-patterns.

# `map f (reverse x)` builds the reversed cons spine first, then
# walks it again under `map`. Swapping the order keeps the same
# result but lets `reverse` traverse the already-mapped spine,
# matching the existing "Move reverse out" family in the default
# group (filter, mapMaybe, catMaybes, lefts, rights).
- warn: {lhs: map f (reverse x), rhs: reverse (map f x), name: "Move reverse out"}

# `head (map f xs)` and `last (map f xs)` allocate the whole mapped
# cons spine even though only one element is ever consumed.
# Applying `f` directly to the chosen element sidesteps the
# intermediate list and its cons cells.
- warn: {lhs: head (map f x), rhs: f (head x), name: "Avoid building intermediate list"}
- warn: {lhs: last (map f x), rhs: f (last x), name: "Avoid building intermediate list"}

- group:
# used for tests, enabled when testing this file
name: testing
Expand Down
27 changes: 27 additions & 0 deletions tests/flag-with-group-performance-length.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---------------------------------------------------------------------
FILE tests/flag-with-group-performance-length.hs
module Verify (a, b, c) where
a fn xs = map fn (reverse xs)
b fn xs = head (map fn xs)
c fn xs = last (map fn xs)
RUN "--with-group=performance" tests/flag-with-group-performance-length.hs
OUTPUT
tests/flag-with-group-performance-length.hs:2:11-29: Warning: Move reverse out
Found:
map fn (reverse xs)
Perhaps:
reverse (map fn xs)

tests/flag-with-group-performance-length.hs:3:11-26: Warning: Avoid building intermediate list
Found:
head (map fn xs)
Perhaps:
fn (head xs)

tests/flag-with-group-performance-length.hs:4:11-26: Warning: Avoid building intermediate list
Found:
last (map fn xs)
Perhaps:
fn (last xs)

3 hints