😊
【Elixir v1.12】tap/2, then/2が便利
Elixirのv1.12が5/19にリリースされておよそ1か月ほど経ちました。v1.12では新しく Kernel.then/2
, Kernel.tap/2
という関数が追加されています。こちらが地味に便利なので解説してみます。
then/2
then/2
は第1引数の値を第2引数の関数に渡し、その結果を返します。
iex> 1 |> then(fn x -> x * 2 end)
2
pipeをつなげていく中で引数の順番を変えたい場合に有用です。
iex> "some text" |> then(&File.write!("out.txt", &1))
:ok
これまで then/2
がない場合には、次のように書く必要がありました。thenを使った方がスッキリして良いですね。
iex> "some text" |> (&File.write!("out.txt", &1)).()
:ok
tap/2
tap/2
はthen/2
同様、第1引数の値を第2引数で指定した関数に渡して実行しますが、第1引数に渡した値自体をそのまま返します。
iex> tap(1, fn x -> x + 1 end)
1
pipeの間にログ出力を挟むなど、pipeの中で出力を変えずに別の処理を行いたい場合に便利です。
some_func()
|> tap(&Logger.info/1)
|> other_func()
IO.inspectのように「pipeの流れ自体は変えたくないけど、処理を挟みたい」というケースが出てきたら tap/2
を使うと良さそうです。
コード例
公式ブログに載っているコードブロックが分かりやすいのでこちらにも置いておきます。tap/2
, then/2
を使った方が明らかにスッキリしていますね。
tap/2, then/2を利用した場合
"hello world"
|> tap(&IO.puts/1)
|> then(&Regex.scan(~r/\w+/, &1))
tap/2, then/2を利用しない場合
"hello world"
|> (fn x ->
IO.puts(x)
x
end).()
|> (&Regex.scan(~r/\w+/, &1)).()
まとめ
Elixir v1.12から導入された Kernel.then/2
, Kernel.tap/2
を紹介しました。公式ブログ内の記述でも、
- tap/2とthen/2はどちらもマクロとして実装されている
- Erlang/OTP 24ではコンパイラの改良により、中間の無名関数が最適化されている
とのことですので、無名関数をthenやtapを利用して繋げるのはパフォーマンス的にも問題なさそうです。ぜひ活用ください。
参考
Discussion
この例はiexではありませんが、v1.12から
iex
でも|>
を使えばv/0
と同じように前のコマンドの結果を引き込んでくれるので、ちょっと煩くなりますがpipeもiexにコピペできるようになりました。