Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most idiomatic way to call fb() only if fa() succeeds

I have two functions, I want to run step_1, then run step_2 only if step_1 was ok. Whats the most functionally idiomatic way to structure this code? Nesting case statements seems ugly but I'm not sure how else to do it besides an if which is even worse.

defmodule Test do
  def step_1 do
    IO.puts "Step 1"
    :error
  end

  def step_2 do
    IO.puts "Step 2"
    :ok
  end

  def do_something_case do
    case step_1 do
      :ok ->
        case step_2 do
          :ok -> {:ok}
          :error -> {:error, :step_2}
        end
      :error -> {:error, :step_1}
    end
  end

  def do_something_if do
    r1 = step_1
    if r1 == :ok
      r2 = step_2
      if r2 == :ok
        :ok
      else
        {:error, :step_2}
      end
    else
      {:error, :step_1}
    end
  end
end
like image 782
Soup Avatar asked Feb 09 '23 18:02

Soup


1 Answers

A common way to solve this problem (without a monad library) is to pattern match on the arguments of the functions and pipe them together.

defmodule Test do
  def step_1 do
    IO.puts "Step 1"
    :error
  end

  def step_2(:ok) do
    IO.puts "Step 2"
    :ok
  end
  def step_2({:error, _reason} = error) do
    error
  end

  def do_something_pipeline do
    step_1
    |> step_2
  end
end
like image 63
Gazler Avatar answered Feb 24 '23 01:02

Gazler