Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Manage the zoo with pipes

manage_the_zoo_with_pipes.livemd

Manage the zoo with pipes

Try it yourself!

Run in Livebook

Functions to categorize animals

is_bird? = fn
  "🦉" -> true
  "🦩" -> true
  _other -> false
end

is_brown? = fn
  "🦉" -> true
  "🐻" -> true
  _other -> false
end

We have the following animals in our zoo

animals = ["🦉", "🦉", "🦩", "🦩", "🦩", "🐻", "🐻"]

How many brown birds are there?

Filter all the birds
birds = Enum.filter(animals, is_bird?)
Filter all brown animals from the birds
brown_birds = Enum.filter(birds, is_brown?)
Count the brown birds and print the result
"Number of brown birds: #{length(brown_birds)}"

The pipe operator

The pipe operator is written as |>. It links the result of the expression on the left side of the pipe to the function on the left side. It does this by passing the result of the expression to the functions as first argument. The following:

length(animals)

Is therefore the same as this:

animals |> length()

A function that is piped into can have multiple arguments. The pipe will always provide the result from the expression to the left of the pipe as first argument to the function on the rigt of the pipe. The other arguments must be provided manually.

animals |> Enum.filter(is_bird?)

Here the list of animals is provided to the Enum.filter/2 function as the first argument and the variable is_bird? is provided manually as second argument.

Compose the steps using pipes

With this in mind, the steps to determine the number of brown birds can be composed with pipes.

animals
|> Enum.filter(is_bird?)
|> Enum.filter(is_brown?)
|> length()
|> then(fn number_of_brown_birds -> "Number of brown birds: #{number_of_brown_birds}" end)

Compose with pipes

Pipes are a great tool to compose functions that solve small problems to solve bigger problems while keeping the code clean and easy to understand.

count_brown = fn animals_to_count ->
  animals_to_count
  |> Enum.filter(is_brown?)
  |> length
end

print_count = fn count, category ->
  IO.puts("Number of #{category}: #{count}")
end

animals
|> length()
|> print_count.("animals")

animals
|> count_brown.()
|> print_count.("brown animals")

animals
|> Enum.filter(is_bird?)
|> count_brown.()
|> print_count.("brown birds")

animals
|> Enum.reject(is_bird?)
|> count_brown.()
|> print_count.("brown none-birds")