# Enum.reduce_while vs Enum.reduce

Dear Team,
Below are two functions. And i am beginner in ELIXIR
a) The first one uses Enum_reduce_while
b) the second function uses Enum_reduce

I am observing the following
a) in the first function teh count goes from 0 , 1 , 2, 3 and gets reset (Basically for each row, the count gets reset) when i see the values using print. I was expecting the count to keep incrementing.
b) However in the 2nd function the count keeps incremeting (which is expected). The only difference is that the first one is reduce_while.

Questions
a) We may say that the 2nd Enumâ€™s return is not assigned in Enum_reduce_while. But thatâ€™s the same i have done in the next function.

Why is this so and what am i missing?

Sincerely,
Arvind
def is_power_pattern_present_in_grid(grid,pattern,max_row,max_col) when length(pattern) <= max_row*max_col do
count = 0
result = 0
{chk, chk1} =
Enum.reduce_while(0â€¦max_row-1, {result,count}, fn row,{result,count} â†’
Enum.reduce_while(0â€¦max_col-1, {result,count}, fn col,{result,count} â†’
IO.puts(â€ślooping throughat #{inspect(row)}, #{inspect(col)},#{inspect(count)}â€ť)
count = count + 1
result = 0
{:cont,{result,count}}
end)
{:cont,{result,count}}
end)
end

def is_power1_pattern_present_in_grid(grid,pattern,max_row,max_col) when length(pattern) <= max_row*max_col do
count = 0
result = 0
{chk, chk1} =
Enum.reduce(0â€¦max_row-1, {result,count}, fn row,{result,count} â†’
Enum.reduce(0â€¦max_col-1, {result,count}, fn col,{result,count} â†’
IO.puts(â€ślooping throughat #{inspect(row)}, #{inspect(col)},#{inspect(count)}â€ť)
count = count + 1
result = 0
{result,count}
end)
end)
end

Hi, @SudarsanD you can use
`````
`````
to format your code example like this:

``````def foo(x) do
x * 2
end
``````
3 Likes

In the first function the outer `Enum.reduce` does not get the result from the inner `Enum.reduce`. To align the functions, the first function would have to look like this:

``````  def is_power_pattern_present_in_grid(_grid, pattern, max_row, max_col)
when length(pattern) <= max_row * max_col do
count = 0
result = 0

Enum.reduce_while(0..(max_row - 1), {result, count}, fn row, {result, count} ->
{result, count} = Enum.reduce_while(0..(max_col - 1), {result, count}, fn col, {result, count} ->
IO.puts("looping throughat #{inspect(row)}, #{inspect(col)},#{inspect(count)}")
count = count + 1
result = 0
{:cont, {result, count}}
end)

{:cont, {result, count}}
end)
end
``````

Another tip: take a look in the docs for Comprehensions - The Elixir programming language

3 Likes

Building on this youâ€™re re-using the same variable names in both loops, which can lead to confusion when coming from a mutable language because you may be expecting the inner loop to affect the outer loopâ€™s variables, but Elixir sees your loop as the way I renamed the acc values:

``````Enum.reduce_while(0..(max_row - 1), {result, count}, fn row, {result_out, count_out} ->
Enum.reduce_while(0..(max_col - 1), {result_out, count_out}, fn col, {result_in, count_in} ->
IO.puts("looping throughat #{inspect(row)}, #{inspect(col)},#{inspect(count_in)}")

count_in = count_in + 1
result_in = 0
{:cont, {result_in, count_in}}
end)

{:cont, {result_out, count_out}}
end)
``````

That makes it clear that youâ€™re not re-binding the `_out` values with the result of the inner loop. Every time through, the inner loop gets the original `{:cont, {0, 0}}` unless you re-bind the return of the inner loop to the outerâ€™s accumulator variables.

``````Enum.reduce_while(0..(max_row - 1), {result, count}, fn row, {result_out, count_out} ->
{result_out, count_out} =
Enum.reduce_while(0..(max_col - 1), {result_out, count_out}, fn col, {result_in, count_in} ->
IO.puts("looping throughat #{inspect(row)}, #{inspect(col)},#{inspect(count_in)}")

count_in = count_in + 1
result_in = 0
{:cont, {result_in, count_in}}
end)

{:cont, {result_out, count_out}}
end)
``````

Whereas in the `reduce` function, the inner loopâ€™s return value gets set as the outer loopâ€™s accumulator automatically because it is the last value in the loop. Hope that makes sense.

3 Likes

Thanks a lot for the replies. However what i dont understand is that even in Enum.reduce_while, the last line executed is either {:cont, {result,count}}. Why in that case the inner loopâ€™s return value is not set as the outer loopâ€™s accumulator?.

Sincerely,
Arvind

From the docs:

The return value for `fun` is expected to be

• `{:cont, acc}` to continue the reduction with `acc` as the new accumulator or
• `{:halt, acc}` to halt the reduction

If `fun` returns `{:halt, acc}` the reduction is halted and the function returns `acc`. Otherwise, if the enumerable is exhausted, the function returns the accumulator of the last `{:cont, acc}`.

Whether you `:halt` or let it run its course through the whole loop by only returning `:cont`, itâ€™s still only going to output the `acc` to the outer loop.

You must catch the `acc` value that it returns and explicitly include it in the outer loopâ€™s `{:cont, ...}` so that the outer loop can also know to continue.

The inner Enum.reduce_while returns {:cont, {result,count}. However we simply take the last 2 values of it. Is it a special case? . I tried to write a function which returns 3 values, but assign the functionsâ€™ output to two values and the compilation throws an error.

how come in this case, this is not shown as an error?

Sincerely,
Sudarsan.D

It does not return the `:cont` part, you use that as part of the implementation of `reduce_while` to tell it to keep looping. Since you never tell it to `:halt` it gets to the end of the loop and returns only the accumulator `{result_in, count_in}` to the outside loop. At that point you want to bind the returned tuple to the outer variables by pattern matching, which happens at the `{result_out, count_out} = Enum.reduce_while` line

Thanks a lot. This helps me to understand Enum.reduce_while. But why this kind of binding the returned tuple to the outer variables is not needed when we use Enum.reduce?.

Specifically you mentioned â€śWhereas in the reduce function, the inner loopâ€™s return value gt set as the outer loops accumulator automatically because it is the last value in the loopâ€ť. Now even with reduce_while, the inner_loop return value is {result_out,count_out}. This should have been set automatically to the outer loopâ€™s accumulator?. Why this is not happening with reduce_while.

Sincerely,
Sudarsan.D

Sincerely,
Sudarsan.D

Iâ€™m sorry that I couldnâ€™t explain that better. It happens that the inner reduce already returns the same shape expected by the outer one, but reduce_while is different because you have to set either :halt or :cont explicitly so you mist capture the return values of the inner loop and create the :cont tuple.

Iâ€™ll see if I can provide some better examples tomorrow (Iâ€™m on mobile now) this all has to do with the fundamental concept of immutability, as well as understanding how these two functions differ in implementation.

Hi @SudarsanD , the result of a function is the last expression. In your `Enum.reduce` example the last expression is the result from the inner `Enum.reduce`. In your `Enum.reduce_while` example the last expression is `{:cont, {result, count}}` and `result` and `count` are exactly the same bindings as the inputs of the anonymous function for the outer `Enum.reduce_while`. The anonymous function for the inner `Enum.reduce_while` shadows the vars `result` and `count`. That means the vars `result` and `count` for the inner function and the outer function are different bindings.

I have also simplified your example:

``````defmodule Foo do
def bar1(as, bs) do
Enum.reduce(as, 0, fn a, count ->
IO.inspect([count: count, a: a], label: :outer)

Enum.reduce(bs, count, fn b, count ->
IO.inspect([count: count, a: a, b: b], label: :inner)
count = count + 1
count
end)
end)
end

def bar2(as, bs) do
Enum.reduce(as, 0, fn a, count ->
IO.inspect([count: count, a: a], label: :outer)

Enum.reduce_while(bs, count, fn b, count ->
IO.inspect([count: count, a: a, b: b], label: :inner)
count = count + 1
{:cont, count}
end)
end)
end

def bar3(as, bs) do
Enum.reduce_while(as, 0, fn a, count ->
IO.inspect([count: count, a: a], label: :outer)

Enum.reduce_while(bs, count, fn b, count ->
# The "inner" count shadows the "outer" count
IO.inspect([count: count, a: a, b: b], label: :inner)
count = count + 1
{:cont, count}
end)

{:cont, count}
end)
end

def bar4(as, bs) do
Enum.reduce_while(as, 0, fn a, count ->
IO.inspect([count: count, a: a], label: :outer)

count = Enum.reduce_while(bs, count, fn b, count ->
# The "inner" count shadows the "outer" count
IO.inspect([count: count, a: a, b: b], label: :inner)
count = count + 1
{:cont, count}
end)

{:cont, count}
end)
end
end
``````
``````iex(1)> Foo.bar1(0..1, 0..1)
outer: [count: 0, a: 0]
inner: [count: 0, a: 0, b: 0]
inner: [count: 1, a: 0, b: 1]
outer: [count: 2, a: 1]
inner: [count: 2, a: 1, b: 0]
inner: [count: 3, a: 1, b: 1]
4
iex(2)> Foo.bar2(0..1, 0..1)
outer: [count: 0, a: 0]
inner: [count: 0, a: 0, b: 0]
inner: [count: 1, a: 0, b: 1]
outer: [count: 2, a: 1]
inner: [count: 2, a: 1, b: 0]
inner: [count: 3, a: 1, b: 1]
4
iex(3)> Foo.bar3(0..1, 0..1)
outer: [count: 0, a: 0]
inner: [count: 0, a: 0, b: 0]
inner: [count: 1, a: 0, b: 1]
outer: [count: 0, a: 1]
inner: [count: 0, a: 1, b: 0]
inner: [count: 1, a: 1, b: 1]
0
iex(4)> Foo.bar4(0..1, 0..1)
outer: [count: 0, a: 0]
inner: [count: 0, a: 0, b: 0]
inner: [count: 1, a: 0, b: 1]
outer: [count: 2, a: 1]
inner: [count: 2, a: 1, b: 0]
inner: [count: 3, a: 1, b: 1]
4
``````

In `Foo.bar3` you can see that the accumulator for the outer `Enum.reduce_while` is not changed because the result of the inner `Enum.reduce_while` is lost. In `Foo.bar4` the accumulator is updated with the result of the inner `Enum.reduce_while`.

2 Likes