5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

forをパイプの中で使用する…のはオススメで無い

Last updated at Posted at 2018-10-07

fukuoka.ex代表のpiacereです
今回もご覧いただいて、ありがとうございます:bow:

前回のコラムで、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を使うことが得策でしょう

p.s.「いいね」よろしくお願いします

よろしければ、ページ左上の image.pngimage.png のクリックをお願いしますー:bow:

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?