Skip to content

Commit 1c834e8

Browse files
author
José Valim
committed
Make the reducer function part of the suspended continuation
1 parent 8e51528 commit 1c834e8

File tree

5 files changed

+73
-60
lines changed

5 files changed

+73
-60
lines changed

lib/elixir/lib/enum.ex

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,9 @@ defprotocol Enumerable do
8080
8181
The continuation is the closure returned as result when
8282
the enumeration is suspended. When invoked, it expects
83-
an accumulator and a reducer function as argument, it returns
84-
the result.
83+
a new accumulator and it returns the result.
8584
"""
86-
@type continuation :: (acc, reducer -> result)
85+
@type continuation :: (acc -> result)
8786

8887
@doc """
8988
The reduce function.
@@ -94,10 +93,10 @@ defprotocol Enumerable do
9493
9594
As an example, here is the implementation of `reduce` for lists:
9695
97-
def reduce(_, { :halt, acc }, _fun), do: { :halted, acc }
98-
def reduce(list, { :suspend, acc }, _fun), do: { :suspended, acc, &reduce(list, &1, &2) }
99-
def reduce([], { :cont, acc }, _fun), do: { :done, acc }
100-
def reduce([h|t], { :cont, acc }, fun), do: reduce(t, fun.(h, acc), fun)
96+
def reduce(_, { :halt, acc }, _fun), do: { :halted, acc }
97+
def reduce(list, { :suspend, acc }, fun), do: { :suspended, acc, &reduce(list, &1, fun) }
98+
def reduce([], { :cont, acc }, _fun), do: { :done, acc }
99+
def reduce([h|t], { :cont, acc }, fun), do: reduce(t, fun.(h, acc), fun)
101100
102101
"""
103102
@spec reduce(t, acc, reducer) :: result
@@ -905,17 +904,16 @@ defmodule Enum do
905904

906905
def reduce(collection, fun) do
907906
result =
908-
Enumerable.reduce(collection, { :cont, nil }, fn x, _ ->
909-
{ :suspend, x }
910-
end)
907+
Enumerable.reduce(collection, { :cont, :first }, fn
908+
x, :first ->
909+
{ :cont, { :acc, x } }
910+
x, { :acc, acc } ->
911+
{ :cont, { :acc, fun.(x, acc) } }
912+
end) |> elem(1)
911913

912914
case result do
913-
{ :suspended, x, continuation } ->
914-
continuation.({ :cont, x }, fn x, acc ->
915-
{ :cont, fun.(x, acc) }
916-
end) |> elem(1)
917-
{ _, _ } ->
918-
raise Enum.EmptyError
915+
:first -> raise Enum.EmptyError
916+
{ :acc, acc } -> acc
919917
end
920918
end
921919

@@ -1957,10 +1955,10 @@ defmodule Enum do
19571955
end
19581956

19591957
defimpl Enumerable, for: List do
1960-
def reduce(_, { :halt, acc }, _fun), do: { :halted, acc }
1961-
def reduce(list, { :suspend, acc }, _fun), do: { :suspended, acc, &reduce(list, &1, &2) }
1962-
def reduce([], { :cont, acc }, _fun), do: { :done, acc }
1963-
def reduce([h|t], { :cont, acc }, fun), do: reduce(t, fun.(h, acc), fun)
1958+
def reduce(_, { :halt, acc }, _fun), do: { :halted, acc }
1959+
def reduce(list, { :suspend, acc }, fun), do: { :suspended, acc, &reduce(list, &1, fun) }
1960+
def reduce([], { :cont, acc }, _fun), do: { :done, acc }
1961+
def reduce([h|t], { :cont, acc }, fun), do: reduce(t, fun.(h, acc), fun)
19641962

19651963
def member?([], _), do: false
19661964
def member?(list, value), do: :lists.member(value, list)

lib/elixir/lib/hash_dict.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ defmodule HashDict do
330330

331331
# Reduces the bucket
332332
defp bucket_reduce(_, { :halt, acc }, _fun), do: { :halted, acc }
333-
defp bucket_reduce(list, { :suspend, acc }, _fun), do: { :suspended, acc, &bucket_reduce(list, &1, &2) }
333+
defp bucket_reduce(list, { :suspend, acc }, fun), do: { :suspended, acc, &bucket_reduce(list, &1, fun) }
334334
defp bucket_reduce([[k|v]|t], { :cont, acc }, fun), do: bucket_reduce(t, fun.({ k, v }, acc), fun)
335335
defp bucket_reduce([], { :cont, acc }, _fun), do: { :done, acc }
336336

@@ -401,8 +401,8 @@ defmodule HashDict do
401401
{ :halted, acc }
402402
end
403403

404-
defp node_reduce(list, -1, { :suspend, acc }, _fun, count, next) do
405-
{ :suspended, acc, &node_reduce(list, -1, &1, &2, count, next) }
404+
defp node_reduce(list, -1, { :suspend, acc }, fun, count, next) do
405+
{ :suspend, acc, &node_reduce(list, -1, &1, fun, count, next) }
406406
end
407407

408408
defp node_reduce([[k|v]|t], -1, { :cont, acc }, fun, _count, next) do

lib/elixir/lib/hash_set.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,10 @@ defmodule HashSet do
304304
{ [], 0 }
305305
end
306306

307-
defp bucket_reduce(_, { :halt, acc }, _fun), do: { :halted, acc }
308-
defp bucket_reduce(list, { :suspend, acc }, _fun), do: { :suspended, acc, &bucket_reduce(list, &1, &2) }
309-
defp bucket_reduce([h|t], { :cont, acc }, fun), do: bucket_reduce(t, fun.(h, acc), fun)
310-
defp bucket_reduce([], { :cont, acc }, _fun), do: { :done, acc }
307+
defp bucket_reduce(_, { :halt, acc }, _fun), do: { :halted, acc }
308+
defp bucket_reduce(list, { :suspend, acc }, fun), do: { :suspended, acc, &bucket_reduce(list, &1, fun) }
309+
defp bucket_reduce([h|t], { :cont, acc }, fun), do: bucket_reduce(t, fun.(h, acc), fun)
310+
defp bucket_reduce([], { :cont, acc }, _fun), do: { :done, acc }
311311

312312
defp bucket_fold(bucket, acc, fun) do
313313
:lists.foldl(fun, acc, bucket)
@@ -399,8 +399,8 @@ defmodule HashSet do
399399
{ :halted, acc }
400400
end
401401

402-
defp node_reduce(list, -1, { :suspend, acc }, _fun, count, next) do
403-
{ :suspended, acc, &node_reduce(list, -1, &1, &2, count, next) }
402+
defp node_reduce(list, -1, { :suspend, acc }, fun, count, next) do
403+
{ :suspended, acc, &node_reduce(list, -1, &1, fun, count, next) }
404404
end
405405

406406
defp node_reduce([h|t], -1, { :cont, acc }, fun, _count, next) do

lib/elixir/lib/range.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ defimpl Enumerable, for: Range do
2525
{ :halted, acc }
2626
end
2727

28-
defp reduce(x, y, { :suspend, acc }, _fun, next, up) do
29-
{ :suspended, acc, &reduce(x, y, &1, &2, next, up) }
28+
defp reduce(x, y, { :suspend, acc }, fun, next, up) do
29+
{ :suspended, acc, &reduce(x, y, &1, fun, next, up) }
3030
end
3131

3232
defp reduce(x, y, { :cont, acc }, fun, next, true) when x <= y do

lib/elixir/lib/stream.ex

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -106,25 +106,24 @@ defmodule Stream do
106106
end
107107

108108
defp do_reduce(Lazy[enum: enum, funs: funs, accs: accs], acc, fun) do
109-
do_reduce(&Enumerable.reduce(enum, &1, &2), :lists.reverse(accs), funs, acc, fun)
109+
composed = :lists.foldl(fn fun, acc -> fun.(acc) end, fun, funs)
110+
do_each(&Enumerable.reduce(enum, &1, composed), :lists.reverse(accs), acc)
110111
end
111112

112-
defp do_reduce(_reduce, _accs, _funs, { :halt, acc }, _fun) do
113+
defp do_each(_reduce, _accs, { :halt, acc }) do
113114
{ :halted, acc }
114115
end
115116

116-
defp do_reduce(reduce, accs, funs, { :suspend, acc }, _fun) do
117-
{ :suspended, acc, &do_reduce(reduce, accs, funs, &1, &2) }
117+
defp do_each(reduce, accs, { :suspend, acc }) do
118+
{ :suspended, acc, &do_each(reduce, accs, &1) }
118119
end
119120

120-
defp do_reduce(reduce, accs, funs, { :cont, acc }, fun) do
121-
composed = :lists.foldl(fn fun, acc -> fun.(acc) end, fun, funs)
122-
123-
case reduce.({ :cont, [acc|accs] }, composed) do
121+
defp do_each(reduce, accs, { :cont, acc }) do
122+
case reduce.({ :cont, [acc|accs] }) do
124123
{ reason, [acc|_] } ->
125124
{ reason, acc }
126125
{ :suspended, [acc|accs], continuation } ->
127-
{ :suspended, acc, &do_reduce(continuation, accs, funs, &1, &2) }
126+
{ :suspended, acc, &do_each(continuation, accs, &1) }
128127
end
129128
end
130129
end
@@ -241,20 +240,21 @@ defmodule Stream do
241240
lazy enum, fn(f1) ->
242241
fn(entry, acc) ->
243242
enum = f.(entry)
244-
do_flat_map(&Enumerable.reduce(enum, &1, &2), { :cont, acc }, f1)
243+
fun = &do_flat_map_each(f1, &1, &2)
244+
do_flat_map(&Enumerable.reduce(enum, &1, fun), { :cont, acc })
245245
end
246246
end
247247
end
248248

249-
defp do_flat_map(reduce, acc, f1) do
249+
defp do_flat_map(reduce, acc) do
250250
try do
251-
reduce.(acc, &do_flat_map_each(f1, &1, &2))
251+
reduce.(acc)
252252
catch
253253
{ :stream_flat_map, acc } -> acc
254254
else
255255
{ :done, acc } -> { :cont, acc }
256256
{ :halted, acc } -> { :cont, acc }
257-
{ :suspended, acc, c } -> { :suspend, acc, &do_flat_map(c, &1, &2) }
257+
{ :suspended, acc, c } -> { :suspend, acc, &do_flat_map(c, &1) }
258258
end
259259
end
260260

@@ -400,20 +400,21 @@ defmodule Stream do
400400
end
401401

402402
defp do_concat(enumerables, acc, fun) do
403+
fun = &do_concat_each(fun, &1, &2)
403404
Enumerable.reduce(enumerables, acc, fn x, acc ->
404-
do_concat_reduce(&Enumerable.reduce(x, &1, &2), { :cont, acc }, fun)
405+
do_concat_reduce(&Enumerable.reduce(x, &1, fun), { :cont, acc })
405406
end)
406407
end
407408

408-
defp do_concat_reduce(reduce, acc, fun) do
409+
defp do_concat_reduce(reduce, acc) do
409410
try do
410-
reduce.(acc, &do_concat_each(fun, &1, &2))
411+
reduce.(acc)
411412
catch
412413
{ :stream_concat, acc } -> acc
413414
else
414415
{ :done, acc } -> { :cont, acc }
415416
{ :halted, acc } -> { :cont, acc }
416-
{ :suspended, acc, c } -> { :suspend, acc, &do_concat_reduce(c, &1, &2) }
417+
{ :suspended, acc, c } -> { :suspend, acc, &do_concat_reduce(c, &1) }
417418
end
418419
end
419420

@@ -439,26 +440,28 @@ defmodule Stream do
439440
"""
440441
@spec cycle(Enumerable.t) :: t
441442
def cycle(enumerable) do
442-
reduce = &Enumerable.reduce(enumerable, &1, &2)
443-
&do_cycle(reduce, reduce, &1, &2)
443+
fn acc, fun ->
444+
reduce = &Enumerable.reduce(enumerable, &1, fun)
445+
do_cycle(reduce, reduce, acc)
446+
end
444447
end
445448

446-
defp do_cycle(_reduce, _cycle, { :halt, acc }, _fun) do
449+
defp do_cycle(_reduce, _cycle, { :halt, acc }) do
447450
{ :halted, acc }
448451
end
449452

450-
defp do_cycle(reduce, cycle, { :suspend, acc }, _fun) do
451-
{ :suspended, acc, &do_cycle(reduce, cycle, &1, &2) }
453+
defp do_cycle(reduce, cycle, { :suspend, acc }) do
454+
{ :suspended, acc, &do_cycle(reduce, cycle, &1) }
452455
end
453456

454-
defp do_cycle(reduce, cycle, acc, fun) do
455-
case reduce.(acc, fun) do
457+
defp do_cycle(reduce, cycle, acc) do
458+
case reduce.(acc) do
456459
{ :done, acc } ->
457-
do_cycle(cycle, cycle, { :cont, acc }, fun)
460+
do_cycle(cycle, cycle, { :cont, acc })
458461
{ :halted, acc } ->
459462
{ :halted, acc }
460463
{ :suspended, acc, continuation } ->
461-
{ :suspended, acc, &do_cycle(continuation, cycle, &1, &2) }
464+
{ :suspended, acc, &do_cycle(continuation, cycle, &1) }
462465
end
463466
end
464467

@@ -494,7 +497,19 @@ defmodule Stream do
494497
"""
495498
@spec repeatedly((() -> element)) :: t
496499
def repeatedly(generator_fun) when is_function(generator_fun, 0) do
497-
unfold(:repeat, fn :repeat -> { generator_fun.(), :repeat } end)
500+
&do_repeatedly(generator_fun, &1, &2)
501+
end
502+
503+
defp do_repeatedly(generator_fun, { :suspend, acc }, fun) do
504+
{ :suspended, acc, &do_repeatedly(generator_fun, &1, fun) }
505+
end
506+
507+
defp do_repeatedly(_generator_fun, { :halt, acc }, _fun) do
508+
{ :halted, acc }
509+
end
510+
511+
defp do_repeatedly(generator_fun, { :cont, acc }, fun) do
512+
do_repeatedly(generator_fun, fun.(generator_fun.(), acc), fun)
498513
end
499514

500515
@doc """
@@ -553,8 +568,8 @@ defmodule Stream do
553568
&do_unfold(next_acc, next_fun, &1, &2)
554569
end
555570

556-
defp do_unfold(next_acc, next_fun, { :suspend, acc }, _fun) do
557-
{ :suspended, acc, &do_unfold(next_acc, next_fun, &1, &2) }
571+
defp do_unfold(next_acc, next_fun, { :suspend, acc }, fun) do
572+
{ :suspended, acc, &do_unfold(next_acc, next_fun, &1, fun) }
558573
end
559574

560575
defp do_unfold(_next_acc, _next_fun, { :halt, acc }, _fun) do

0 commit comments

Comments
 (0)