fukuoka.ex代表のpiacereです
今回もご覧いただいて、ありがとうございます
前回のコラムで、forが、可変長引数を取る関数であることを解明しました
このことを利用して、パイプの中で、forを使う方法について解説します
パイプでforの第1引数を渡す
forは、以下のように、第1引数にリストの分解、第2引数以降に「リストの分解」「条件判定」を複数取り、最後に「do:」を取ります
iex> for x <- [ 1, 3, 5 ], do: x + 2
[3, 5, 7]
iex> for x <- [ 1, 3, 5 ], x < 4, do: x
[1, 3]
iex> for x <- [ 1, 3, 5 ], y <- [ 2, 4, 6 ], x < 4, y < 5, do: x + y
[3, 5, 5, 7]
iex> for x <- [ 1, 3, 5 ], x < 4, y <- [ 2, 4, 6 ], y < 5, do: x + y
[3, 5, 5, 7]
これをパイプで書き直すと、こうなります
iex> ( x <- [ 1, 3, 5 ] ) |> for( do: x + 2 )
[3, 5, 7]
なお、if同様、パイプで渡す部分をカッコで囲まないと、うまく動きませんので、注意してください
forをパイプの中で使えるか?
リスト分解する部分は、単独での実行はできません
iex> x <- [ 1, 3, 5 ]
** (CompileError) iex:76: undefined function <-/2
iex> ( x <- [ 1, 3, 5 ] )
** (CompileError) iex:76: undefined function <-/2
Kernelモジュールや、Kernel.SpecialFormsモジュール等のどこにも定義されておらず、for特有の記述のようです(withでも使えるので、正確には、forとwithに特有、ですが)
リファレンスでの「<-」の検索結果
https://hexdocs.pm/elixir/search.html?q=%3C-
アリティも存在しません
iex> &<-/0
** (UndefinedFunctionError) function :erl_eval.<-/0 is undefined or private
iex> &<-/1
** (UndefinedFunctionError) function :erl_eval.<-/1 is undefined or private
iex> &<-/2
** (UndefinedFunctionError) function :erl_eval.<-/2 is undefined or private
iex> &<-/3
** (UndefinedFunctionError) function :erl_eval.<-/3 is undefined or private
そのため、パイプの後続として、forを使うことはできません
これは以前、「Excelから関数型言語マスター2回目:『列の抽出』と『Web表示』」の「forはforでは無い」の②で挙げた通りで、その背景が、上記「<-」の仕様によるものです
参考程度:パイプの先頭でならforは使える ※非推奨
前回コラムの冒頭にある通り、forはリストを返すことができるため、以下のように、パイプの先頭で使うことは可能です(ま、この例だと、forの中に条件判定書いちゃえるんですが)
iex> ( for x <- [ 1, 3, 5 ], do: x + 2 ) |> Enum.filter( &( &1 < 6 ) )
[3, 5]
しかし、こんなforをカッコで囲むような書き方をする位なら、以下のように、Enum.mapで書いた方が、ナチュラルです
iex> Enum.map( [ 1, 3, 5 ], &( &1 + 2 ) ) |> Enum.filter( &( &1 < 6 ) )
[3, 5]
更に、渡すリストをパイプで繋げ、可読性を良くできるのも、forではできない、Enum.mapらしい書き方でしょう
iex> [ 1, 3, 5 ] |> Enum.map( &( &1 + 2 ) ) |> Enum.filter( &( &1 < 6 ) )
[3, 5]
こうしたことから、パイプの中ではforを使わず、より汎用性高いEnum.mapを使うことが得策でしょう