libo

libo

Strange error with nested Enum.reduce_while

For the following code

      c = %{a: %{}, b: [%{}, %{}]}

      r =
        Enum.reduce_while(c, nil, fn {_k, v}, _acc ->
          case v do
            %{} ->
              {:cont, nil}

            [%{} | _] = list ->
              Enum.reduce_while(list, nil, fn l, _acc ->
                {:cont, nil}
              end)
          end
        end)

The two reduce_while should both end with {:cont, nil} and r should be nil in the end.

However, I got an FunctionClauseError instead:

** (FunctionClauseError) no function clause matching in Enumerable.List.reduce/3    
    
    The following arguments were given to Enumerable.List.reduce/3:
    
        # 1
        []
    
        # 2
        nil
    
        # 3
        #Function<41.105768164/2 in :erl_eval.expr/6>
    
    Attempted function clauses (showing 4 out of 4):
    
        def reduce(_list, {:halt, acc}, _fun)
        def reduce(list, {:suspend, acc}, fun)
        def reduce([], {:cont, acc}, _fun)
        def reduce([head | tail], {:cont, acc}, fun)
    
    (elixir 1.16.0) lib/enum.ex:4839: Enumerable.List.reduce/3
    (elixir 1.16.0) lib/enum.ex:2582: Enum.reduce_while/3
    iex:4: (file)

The error message says the 2nd argument is nil (therefore, cannot match any clause). However, this should not be possible. Because a :cont tuple is guaranteed:

Any idea why it happens? Where does the bug locate, in my code, the standard lib, or even deeper?

Marked As Solved

al2o3cr

al2o3cr

The inner reduce_while here will unwrap {:cont, nil} and return nil.

Last Post!

spacebat

spacebat

I ran into this today, here’s the pattern I ended up with:

iex> Enum.reduce_while([[1, 2, 3, 4], [5, 6, 7, 8]], [], fn list, acc -> 
       Enum.reduce_while(list, {:cont, acc}, fn number, {:cont, acc} ->
         if number < 7 do
           {:cont, {:cont, [number | acc]}}
         else
           {:halt, {:halt, acc}}
         end
       end)
     end)

[6, 5, 4, 3, 2, 1]

The inner :cont/:halt tuples are ultimately for consumption by the outer reduce_while, but the inner reduce_while has to pass them along to itself.

This comprehension isn’t much shorter but is less confusing:

try do
  for list <- [[1, 2, 3, 4], [5, 6, 7, 8]], number <- list, reduce: [] do
    acc ->
      if number < 7 do
        [number | acc]
      else
        throw acc
      end
  end
catch
  x -> x
end

Where Next?

Popular in Questions Top

New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36820 110
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New

We're in Beta

About us Mission Statement