@msimcoe - the pipe operator certainly allows for a really nice, straightforward way to model simple chains of function calls, but it’s good to be aware that there are better options if your needs are more complex
Strictly speaking, using pipes, you could of course handle things like a simple :ok
results etc (that @NobbZ mentioned above) by crafting your functions to handle the outputs from earlier in the pipeline:
defmodule Monitor do
def poll() do
# Let's simulate getting some metric from a device..
x = :rand.uniform(15)
if x <= 12 do
{:ok, x}
else
{:error, :device_failure}
end
end
def check({:ok, x}) when is_integer(x) and x < 10, do: {:ok, x}
def check({:ok, x}) when is_integer(x) and x >= 10, do: {:warning, x}
def check({:error, _reason} = error), do: error
def output({:ok, x}), do: IO.puts("All is ok: #{x}")
def output({:warning, x}), do: IO.puts("WARNING: Check your x, it's getting a bit high: #{x}")
def output({:error, reason}), do: IO.puts("ERROR: #{reason}")
def report() do
poll() |> check() |> output()
end
end
iex(3)> Monitor.report()
WARNING: Check your x, it's getting a bit high: 11
:ok
iex(4)> Monitor.report()
All is ok: 9
:ok
iex(5)> Monitor.report()
ERROR: device_failure
:ok
The above functions, however, are highly coupled to each other, and most likely not useful outside their context, even if they happen to do something that you could otherwise have use for. You might be better served by using with
in a more complex chain like this:
defmodule Monitor do
def poll() do
# Let's simulate getting some metric from a device..
x = :rand.uniform(15)
if x <= 12 do
{:ok, x}
else
{:error, :device_failure}
end
end
def check(x) when is_integer(x) and x < 10, do: {:ok, x}
def check(x) when is_integer(x) and x >= 10, do: {:warning, x}
def report() do
with {:ok, x} <- poll(),
{:ok, x} <- check(x) do
IO.puts("All is ok: #{x}")
else
{:warning, x} -> IO.puts("WARNING: Check your x, it's getting a bit high: #{x}")
{:error, reason} -> IO.puts("ERROR: #{reason}")
end
end
end
Now each function has only its own purpose to worry about, and report
ties it all together, handling the different responses that are possible, while still making the flow clear.