Idiomati c способ раздеться / проверить: ок и тру второй аргумент - PullRequest
0 голосов
/ 17 марта 2020

Мне нравятся каналы, а Elixir - каналы, но, похоже, возвращать также {: ok, actual_return_value}. Есть ли идиома для работы с трубами?

Я сейчас изучаю "Программирующий эликсир", и следующее решение упражнения может быть возможным, но не полным.

File.cwd()
|> IO.puts()

Я не ищу это решение:

{:ok, ret} = File.cwd()
IO.puts(ret)

Ответы [ 3 ]

5 голосов
/ 17 марта 2020

Не существует идиоматического c способа передачи второго аргумента.

препятствует использованию труб в двух случаях:

  • в цепочке только два звена
  • следующая функция в цепочке принимает результат предыдущей функции, а не первый аргумент, или результат обеспечивает нечто отличное от того, что ожидает следующая функция в цепочке.

Всякий раз, когда это имеет смысл, базовая библиотека делает все возможное, чтобы предоставить все необходимое для придания шарма обаянию. Рассмотрим настройки строк. У нас есть две replace/4 функции: String.replace/4 и Regex.replace/4 с почти схожей функциональностью, но первая принимает строку в качестве первого аргумента для создания когда приходит строка, проще разбить ее на цепочки, и последняя принимает регулярное выражение в качестве первого аргумента.

Если вы не уверены в том, как транслировать - это явный признак того, что вы не должны транслировать. Этот простой язык сам по себе намекает на лучший способ go. Действительно, никто не возвращает {:ok, value} из функции, которая всегда выполняется успешно. Тем не менее, может быть какой-то другой результат . В случае, о котором идет речь, {:error, reason}. Дай угадаю: ты не хочешь, чтобы твой код взорвался. И любезно напоминает вам об этом. Конечно, вы все еще можете использовать Kernel.elem/2, но вы действительно хотите? Бьюсь об заклад, нет.

Существует как минимум два разных подхода, в зависимости от того, чего вы на самом деле хотите достичь.

Один из них - использовать монади c SpecialForms.with/1 , который либо продолжает выполнять пункты , либо возвращает первый несопоставленный результат.

with {:ok, a} <- Mod.fun1(),
     {:ok, b} <- Mod.fun2(a),
     {:ok, c} <- Mod.fun3(b),
  do: IO.puts(c)

Таким образом, вы либо выводите c или return первый несопоставленный (читай: ошибочный) результат.

Другой способ - использовать Kernel.SpecialForms.case/2.

File.cwd()
|> case do
  {:ok, result} -> result
  {:error, reason} -> LOG_OR_SOMETHING
end

Выберите любой из ваших вариантов , но помните: труба должна использоваться там, где она есть, а не везде.

2 голосов
/ 17 марта 2020

Все зависит от того, как вы хотите обрабатывать ошибки.

Если вы хотите перейти на возвращаемое значение, вы можете использовать case или with или что-то в этом роде. Если вы поместите его в приватную функцию, он разрешит конвейерную передачу (вы можете подключиться напрямую, но это будет ужасно быстро).

with {:ok, pwd} <- File.cwd() do
  IO.puts(pwd)
end

Если получение ответа, отличного от кортежа ok, является исключительным, вы можете используйте версии функций взрыва.

File.cwd!()
|> IO.puts()

Если ваша функция не имеет версии взрыва, вы можете сделать вспомогательную функцию для выполнения чего-то подобного.

File.cwd()
|> ok!()
|> IO.puts()

defp ok!({:ok, value}), do: value

Если вы На 100% уверены, что функция вернет корректный кортеж, вы можете использовать elem/2, чтобы получить значение из кортежа. Это не так явно, так что это не мой любимый.

File.cwd()
|> elem(1)
|> IO.puts()

При этом поток управления не там, где трубопроводы превышают. Лучше всего, если вы делаете несколько операций для преобразования структуры данных. В такой ситуации вам, вероятно, лучше использовать логические конструкции и разбивать их на более мелкие функции.

0 голосов
/ 17 марта 2020

Если вы хотите напечатать значение в стандартный вывод, у вас есть несколько вариантов, но вот два, наиболее близких к вашему примеру

File.cwd()
|> inspect()
|> IO.puts()

, или вы можете использовать более короткую версию

File.cwd()
|> IO.inspect()

разница в том, что IO.inspect/2 принимает любой термин и возвращает тот же термин, в то время как IO.puts () принимает строку и iolist и возвращает :ok или {:error, ...}, поэтому вам нужно преобразовать значение в строку, если вы хотите использовать IO.puts ().

...