Repository navigation
Scanl fixes - #3259
Merged
Merged
Scanl fixes#3259
Conversation
harendra-kumar
force-pushed
the
scanl-fixes
branch
2 times, most recently
from
October 16, 2026 12:45
859e910 to
1be44b7
Compare
windowRange counted every input in an Int and used min i n as the window length. On a 32-bit Int, e.g. the JavaScript backend, the counter wrapped to a negative value after 2^31 - 1 inputs, giving a ring with a negative size and a wrong range. Stop counting once the window is full. Add tests comparing Fold.windowRange and Scanl.windowRange with a list reference for window sizes 1 to 4. Scanl.windowRange 0, and windowMinimum 0 and windowMaximum 0, failed with the message "ringsOf: window size must be > 0". Name windowRange in the message.
scanRingsOf added the element size to a byte counter on every input and used min offset rSize as the ring size. On a 32-bit Int, e.g. the JavaScript backend, the counter wrapped to a negative value after 2^31 / sizeOf a inputs, e.g. about 268 million Doubles, giving rings with a negative size. Stop counting once the ring is full. Add a test comparing scanRingsOf with a list reference for ring sizes 1 to 4.
The byte counter was saturated with an if-then-else. With GHC 9.14.1 the step of scanRingsOf was then not inlined in the fold loop and the fold state was boxed on every input. Array.createOfLast 1 allocated 8 MB for 100,000 inputs instead of none, and took 4-5 times longer. GHC 9.10.3 inlined the step. Saturate the counter with min instead, GHC 9.14.1 inlines the step with this form.
When the scan for a key terminated on the first input of that key, the
key was neither kept in the map of running scans nor added to the set of
finished keys. The next input with the same key started the scan again
and produced another result. For example, classify fst with the inner
scan "take 1 sum" on [("A",1),("A",2)] emitted Just ("A",1) and
Just ("A",2) instead of Just ("A",1) and Nothing.
Fix classifyGeneric and classifyGenericIO, and with them classify and
classifyIO.
sampleFromthen offset stride kept the elements at the indices i with (i + offset) mod stride == 0, so sampleFromthen 1 3 on [0..9] sampled [2,5,8] instead of [1,4,7]. Keep the indices i >= offset with (i - offset) mod stride == 0. The existing test used offset 0, where the two agree.
When the pipe consumed an input without yielding (SkipC), pipe returned Partial, so the driver emitted the previous output of the scan again. For example, pipe (Pipe.filter even) sum postscanned over [1,2,3,4] gave [0,2,2,6] instead of [2,6]. Return Continue unless the scan returned Partial for an output of the pipe on this input.
uniqBy was rollingMap, whose initial result is error "Empty stream". Using the result before any input failed: Stream.scanl Scanl.uniq on "aab" had the error as its first output, and Scanl.compose Scanl.uniq Scanl.toList failed when it was initialized, compose forces the initial result of the first scan. Implement uniqBy with scanl', the initial result is Nothing.
When one of the two scans returned Done, in step or in initial, partitionByM returned its result without calling final on the other scan, so the other scan's resources were not released. For example, partition (take 1 length) r on [Right 1, Left 2] never ran the final of r. teeWith and Fold.partitionByM finalize the other fold. Call final on the other scan in these cases.
The module doc said that a scan produces an output on each input and that, unlike a pipe, it cannot skip an output. A scan can skip the output on an input using the Continue step, e.g. Scanl.filter. The Min monoid definition in the minimum doc was named maximum and the text called maxBound the default maximum. The doc also said that minimum uses a supplied comparison function, it takes none. The sum doc said that sum is not numerically stable and that scanl' (+) 0 is. sum uses Kahan-Babuska-Neumaier summation, scanl' (+) 0 is the unstable one. The indexingWith doc said that indices start from 0, they start from the given index. The topBy, top and bottom examples converted the output arrays to lists after the stream ended. The outputs share the scan's buffer, which later inputs modify, so the examples showed prefixes of the final buffer, e.g. [17] as the top 1 after the first input, 2. Convert each output with rmapM, and document that the output array is modified by later inputs.
GHC recompiles the test modules that use Template Haskell on every cabal invocation, cabal test spent about 5 minutes rebuilding them after the build step.
Build the master benchmarks on push to master and cache the build directory and the cabal store, pull requests then only run the master benchmarks on the same machine as the PR benchmarks. Cache the bench-runner binary. PERF, packdiff and markdown-doctest run only on pull requests, so their ghcup and hackage index caches were saved separately for each pull request. Restore the ones saved by the TEST workflow on master instead.
The deprecated Prelude tests were built only with the dev flag, in the macOS dev-no-opt job, where Prelude.Async and Prelude.WAsync took about 6 minutes each. Build them with the new deprecated-tests flag instead, in the ubuntu 9.8.4 ci job. The macOS stack job still runs the tests on macOS.
harendra-kumar
force-pushed
the
scanl-fixes
branch
from
October 16, 2026 15:32
1be44b7 to
0d9937f
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.
Bug fixes in the Scanl module, plus a couple of related Fold and RingArray ones: