Idiomatic Approach to using Multiple Function Calls

So I have this problem where I am doing multiple function calls inside a function, and with each function call, I check to see if the result that I am getting is true or not.

For example:

defmodule Example do
  def helper(arr, index_start, index_end) do
    cond do
      index_start > index_end -> false
      arr[index_start] > arr[index_end] -> false
      true ->
        {right, top} = {index_start + 1, index_end + 1}

        res = helper(arr, index_start+right, index_end+top)
        case res do
          true -> true 
          _ -> 
            {left, down} = {index_start - 1, index_end - 1}
            res = helper(arr, index_start-left, index_end-down)

            case res do
              true -> true 
              _ -> 
                {upleft, rightdown} = {index_start + index_end, index_end - index_start}
                res = helper(arr, upleft, rightdown)

                case res do
                  true -> true 
                  _ -> false
                end
            end
        end
    end
  end
end

Btw, this is simply an example code that I just wrote that makes no sense so it might have an issue if you try running it. Just wanted to show what I wanted to do.

Now, over here, I am calling the helper function multiple times and checking its result. What’s the best approach to do something like this in Elixir?

Calling multiple case or cond inside a function makes it very messy. Would appreciate it if someone could explain this using an example.

As a start, have you checked the with keyword?

1 Like

What data structure is arr?
if it’s a map, it can be simplified

defmodule Example do
  def helper(arr, index_start, index_end) when index_start > index_end,
    do: false

  def helper(arr, index_start, index_end) do
    if arr[index_start] > arr[index_end] do
      false
    else
      helper(arr, 2 * index_start + 1, 2 * index_end + 1) or 
      helper(arr, 1, 1) or
      helper(arr, index_start + index_end, index_end - index_start) or
      false
    end
  end
end

This one is more idiomatic,

defmodule Example do
  def helper(arr, index_start, index_end) when index_start > index_end,
    do: false
  
  def helper(arr, index_start, index_end) do
    if arr[index_start] > arr[index_end] do
      false
    else
      helper_right_top(arr, index_start, index_end) or
      helper_left_down(arr, index_start, index_end) or
      helper_upleft_rightdown(arr, index_start, index_end) or
      false

      ## or this fancier version, but you need to make those private functions public
      # Enum.any?([:right_top, :left_down, :upleft_rightdown], fn direction ->
      #   apply(__MODULE__, :"helper_#{direction}", index_start, index_end)
      # end)
    end
  end

  defp helper_right_top(arr, index_start, index_end),
    do: helper(arr, 2 * index_start + 1, 2 * index_end + 1)

  defp helper_left_down(arr, _index_start, _index_end),
    do: helper(arr, 1, 1)

  defp helper_upleft_rightdown(arr, index_start, index_end),
    do: helper(arr, index_start + index_end, index_end - index_start)
end

Now that I have simplified your code, I think it can never return true.

2 Likes

IMO if works much better for boolean conditions. Also you can replace the whole thing by: res == true.

            res = helper(arr, upleft, rightdown)

            case res do
              true -> true 
              _ -> false
            end

Indeed!. In fact in this particular case, since res can only be true or false and is the last evaluation, you can omit the case, and the variable assignment to res and just write

helper(arr, upleft, rightdown)