Ответ 1
Я скопирую материал из моего учебного материала Elixir Express: https://github.com/chrismccord/elixir_express/blob/master/basics/06_pipeline_operator.md
Оператор трубопровода
Одной из самых простых, но эффективных функций в Elixir является оператор конвейера. Оператор конвейера решает проблему, с которой сталкиваются многие функциональные языки при составлении серии преобразований, когда выход из одной функции должен передаваться как входной сигнал другому. Это требует, чтобы решения читались в обратном порядке, чтобы понять действия, выполняемые, затрудняя читаемость и скрывая истинное намерение кода. Эликсир элегантно решает эту проблему, разрешая вывод функции, которая будет передана в качестве первого параметра на вход другого. Во время компиляции функциональная иерархия преобразуется во вложенный "обратный" вариант, который в противном случае потребовался бы.
iex(1)> "Hello" |> IO.puts
Hello
:ok
iex(2)> [3, 6, 9] |> Enum.map(fn x -> x * 2 end) |> Enum.at(2)
18
Чтобы понять всю полезность, предоставляемую конвейером, рассмотрите модуль, который извлекает новые сообщения из API и сохраняет результаты в базе данных. Последовательность шагов:
- Найти учетную запись с помощью авторизованного токена пользователя
- Получить новые сообщения от API с авторизованной учетной записью
- Преобразование ответа JSON на список ключевых слов
- Сохранить все новые сообщения в базе данных
Без трубопровода:
defmodule MessageService do
...
def import_new_messages(user_token) do
Enum.each(
parse_json_to_message_list(
fetch(find_user_by_token(user_token), "/messages/unread")
), &save_message(&1))
end
...
end
Правильное именование и отступы помогают читабельности предыдущего блока, но его намерение не сразу становится очевидным, не затрачивая мгновение на разложение шагов изнутри, чтобы понять понимание потока данных.
Теперь рассмотрим этот ряд шагов с оператором конвейера:
С Pipeline
defmodule MessageService do
...
def import_new_messages(user_token) do
user_token
|> find_user_by_token
|> fetch("/messages/unread")
|> parse_json_to_message_list
|> Enum.each(&save_message(&1))
end
...
end
Проводя результат каждого шага в качестве первого аргумента для следующего, позволяет писать программы в виде серии преобразований, которые любой читатель мог бы сразу прочитать и понять, не затрачивая дополнительных усилий на разворачивание функций, как в первое решение.
Стандартная библиотека Elixir фокусируется на том, чтобы помещать объект функции в качестве первого аргумента, помогая и поощряя естественное использование конвейеров.