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

Pipe Operator

reading/deprecated_pipe_operator.livemd

Pipe Operator

Mix.install([
  {:jason, "~> 1.4"},
  {:kino, "~> 0.9", override: true},
  {:youtube, github: "brooklinjazz/youtube"},
  {:hidden_cell, github: "brooklinjazz/hidden_cell"}
])

Navigation

Return Home Report An Issue

Setup

Ensure you type the ea keyboard shortcut to evaluate all Elixir cells before starting. Alternatively, you can evaluate the Elixir cells as you read.

Lesson

To create more complex behavior, you’ll often compose smaller functions together. Composing functions together reflects nature of problem-solving where we take large problems and break them down into smaller ones.

To help compose functions together, Elixir provides the pipe |> operator. That’s the | symbol likely above your enter key, and the greater than > symbol side by side to make |>.

The pipe operator allows you to take the output of one function and pass it in as an argument for the input of another function.

flowchart LR
  A[Input] --> B[Function1]
  B --> C[Pipe]
  C --> D[Function2]
  D --> E[Output]

Why is this useful? Without the pipe operator you can wind up writing deeply nested function calls.

four.(three.(two.(one.())))

But with the pipe operator, you can chain functions together.

one.() |> two.() |> three.() |> four.()

If a function is called with multiple arguments, the function piped in will be the first argument.

two(1, 2) # how to call two/2 by itself.

# How To Use The Pipe Operator
# To Call The Two/2 With One/1 As The First Argument.
one.() |> two.(2)

You can also pass in a value to a pipe.

1 |> two.()

The pipe operator doesn’t change the behavior of a program. Instead, the pipe operator exists as syntax sugar to improve the clarity of your code.

add_grapes = fn shopping_list -> shopping_list ++ ["grapes"] end
add_pizza = fn shopping_list -> shopping_list ++ ["pizza"] end
add_blueberries = fn shopping_list -> shopping_list ++ ["blueberries"] end

[]
|> add_grapes.()
|> add_pizza.()
|> add_blueberries.()
|> add_pizza.()
|> add_blueberries.()

# Vs The Alternative
add_blueberries.(add_pizza.(add_blueberries.(add_pizza.(add_grapes.([])))))

Mark As Completed

file_name = Path.basename(Regex.replace(~r/#.+/, __ENV__.file, ""), ".livemd")

progress_path = __DIR__ <> "/../progress.json"
existing_progress = File.read!(progress_path) |> Jason.decode!()

default = Map.get(existing_progress, file_name, false)

form =
  Kino.Control.form(
    [
      completed: input = Kino.Input.checkbox("Mark As Completed", default: default)
    ],
    report_changes: true
  )

Task.async(fn ->
  for %{data: %{completed: completed}} <- Kino.Control.stream(form) do
    File.write!(progress_path, Jason.encode!(Map.put(existing_progress, file_name, completed)))
  end
end)

form

Commit Your Progress

Run the following in your command line from the curriculum folder to track and save your progress in a Git commit. Ensure that you do not already have undesired or unrelated changes by running git status or by checking the source control tab in Visual Studio Code.

$ git checkout solutions
$ git checkout -b pipe-operator-reading
$ git add .
$ git commit -m "finish pipe operator reading"
$ git push origin pipe-operator-reading

Create a pull request from your pipe-operator-reading branch to your solutions branch. Please do not create a pull request to the DockYard Academy repository as this will spam our PR tracker.

DockYard Academy Students Only:

Notify your instructor by including @BrooklinJazz in your PR description to get feedback. You (or your instructor) may merge your PR into your solutions branch after review.

If you are interested in joining the next academy cohort, sign up here to receive more news when it is available.