Skip to content

Commit df8955c

Browse files
madlepjosevalim
authored andcommitted
Improve Enum.chunk_while/4 docs to clarify after_fun semantics (#10595)
- add `{:halt, acc}` tuple return doc for `chunk_fun` - explain `after_fun` semantics in more detail - format return tuples for `chunk_fun` and `after_fun` as markdown lists - added note that `acc` in `after_fun` return tuple is ignored - note that `Enum.chunk_while/4` returns a list of *chunks*, not a list of lists (emitted chunks can be anything, not necessarily just lists)
1 parent 6b87a54 commit df8955c

File tree

2 files changed

+32
-9
lines changed

2 files changed

+32
-9
lines changed

lib/elixir/lib/enum.ex

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -473,15 +473,25 @@ defmodule Enum do
473473
@doc """
474474
Chunks the `enumerable` with fine grained control when every chunk is emitted.
475475
476-
`chunk_fun` receives the current element and the accumulator and
477-
must return `{:cont, chunk, acc}` to emit the given chunk and
478-
continue with accumulator or `{:cont, acc}` to not emit any chunk
479-
and continue with the return accumulator.
476+
`chunk_fun` receives the current element and the accumulator and must return:
480477
481-
`after_fun` is invoked when iteration is done and must also return
482-
`{:cont, chunk, acc}` or `{:cont, acc}`.
478+
* `{:cont, chunk, acc}` to emit a chunk and continue with the accumulator
479+
* `{:cont, acc}` to not emit any chunk and continue with the accumulator
480+
* `{:halt, acc}` to halt chunking over the `enumerable`.
483481
484-
Returns a list of lists.
482+
`after_fun` is invoked with the final accumulator when iteration is
483+
finished (or `halt`ed) to handle any trailing elements that were returned
484+
as part of an accumulator, but were not emited as a chunk by `chunk_fun`.
485+
It must return:
486+
487+
* `{:cont, chunk, acc}` to emit a chunk. The chunk will be appended to the
488+
list of already emitted chunks.
489+
* `{:cont, acc}` to not emit a chunk
490+
491+
The `acc` in `after_fun` is required in order to mirror the tuple format
492+
from `chunk_fun` but it will be discarded since the traversal is complete.
493+
494+
Returns a list of emitted chunks.
485495
486496
## Examples
487497
@@ -498,6 +508,8 @@ defmodule Enum do
498508
...> end
499509
iex> Enum.chunk_while(1..10, [], chunk_fun, after_fun)
500510
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
511+
iex> Enum.chunk_while([1, 2, 3, 5, 7], [], chunk_fun, after_fun)
512+
[[1, 2], [3, 5, 7]]
501513
502514
"""
503515
@doc since: "1.5.0"
@@ -512,15 +524,15 @@ defmodule Enum do
512524
{_, {res, acc}} =
513525
Enumerable.reduce(enumerable, {:cont, {[], acc}}, fn entry, {buffer, acc} ->
514526
case chunk_fun.(entry, acc) do
515-
{:cont, emit, acc} -> {:cont, {[emit | buffer], acc}}
527+
{:cont, chunk, acc} -> {:cont, {[chunk | buffer], acc}}
516528
{:cont, acc} -> {:cont, {buffer, acc}}
517529
{:halt, acc} -> {:halt, {buffer, acc}}
518530
end
519531
end)
520532

521533
case after_fun.(acc) do
522534
{:cont, _acc} -> :lists.reverse(res)
523-
{:cont, elem, _acc} -> :lists.reverse([elem | res])
535+
{:cont, chunk, _acc} -> :lists.reverse([chunk | res])
524536
end
525537
end
526538

lib/elixir/test/elixir/enum_test.exs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ defmodule EnumTest do
116116
[[0], [1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
117117

118118
assert Enum.chunk_while([5, 7, 9, 11], [], chunk_fun, after_fun) == [[5, 7, 9]]
119+
120+
assert Enum.chunk_while([1, 2, 3, 5, 7], [], chunk_fun, after_fun) == [[1, 2], [3, 5, 7]]
121+
122+
chunk_fn2 = fn
123+
-1, acc -> {:cont, acc, 0}
124+
i, acc -> {:cont, acc + i}
125+
end
126+
127+
after_fn2 = fn acc -> {:cont, acc, 0} end
128+
129+
assert Enum.chunk_while([1, -1, 2, 3, -1, 4, 5, 6], 0, chunk_fn2, after_fn2) == [1, 5, 15]
119130
end
120131

121132
test "concat/1" do

0 commit comments

Comments
 (0)