Introducing `for let` and `for reduce`

It reduces a small amount of boilerplate in the original example but I agree it is not significant. My hope though is that it reduces the conceptual overhead of reaching to that solution in the first place.

However, I think there are examples where it reduces considerably. Today, as I worked, I tried to see examples where to apply it. Here are two.

This:

    Enum.flat_map_reduce(subs, sources, fn sub, sources ->
      sub_formatter = Path.join(sub, ".formatter.exs")

      if File.exists?(sub_formatter) do
        formatter_opts = eval_file_with_keyword_list(sub_formatter)

        {formatter_opts_and_subs, sources} =
          eval_deps_and_subdirectories(:in_memory, [sub], formatter_opts, sources)

        {[{sub, formatter_opts_and_subs}], sources}
      else
        {[], sources}
      end
    end)

Can be rewritten to this:

   for let(sources),
        sub <- subs,
        sub_formatter = Path.join(sub, ".formatter.exs"),
        File.exists?(sub_formatter) do
      formatter_opts = eval_file_with_keyword_list(sub_formatter)

      {formatter_opts_and_subs, sources} =
        eval_deps_and_subdirectories(:in_memory, [sub], formatter_opts, sources)

      {{sub, formatter_opts_and_subs}, sources}
    end

And this:

  def find_asset_info(notebook, hash) do
    Enum.find_value(notebook.sections, fn section ->
      Enum.find_value(section.cells, fn cell ->
        is_struct(cell, Cell.Elixir) &&
          Enum.find_value(cell.outputs, fn
            {:js_static, %{assets: %{hash: ^hash} = assets_info}, _data} -> assets_info
            {:js_dynamic, %{assets: %{hash: ^hash} = assets_info}, _pid} -> assets_info
            _ -> nil
          end)
      end)
    end)
  end

to this:

  for reduce(value = nil),
      value == nil,
      section <- notebook.sections,
      %Cell.Elixir{} = cell <- section.cells,
      output <- cell.outputs do
    case output do
      {:js_static, %{assets: %{hash: ^hash} = assets_info}, _data} -> assets_info
      {:js_dynamic, %{assets: %{hash: ^hash} = assets_info}, _pid} -> assets_info
      _ -> nil
    end
  end

As soon as you get any kind of nesting, the comprehension format really starts to stand out.

9 Likes