Scala の for 構文はただのリスト内包表記じゃないよ
Scala の for 構文(とりあえずこう呼びます)がただのリスト内包表記なら、いちいちモナドとか言わない方がいいんじゃない?とかいうことを昨日書いたのですが、for 構文は Seq 型だけじゃなくて Option 型とか他の「モナドっぽい」型にも使えるよ、ということをコメントで教えていただきました。
本当だ、こことかこことかに書いてある。明らかに調査不足ですね、すみません。
たとえば以下の2つの関数 fSeq と fOpt、引数や戻り値の型は違いますがまったく同じように定義できます。
これは便利だ。前言撤回します。モナド、モナド。
scala> def fSeq (mx:Seq[Int], my:Seq[Int]) = for (x <- mx; y <- my if (x+y)%3==0) yield x*10+y fSeq: (Seq[Int],Seq[Int])Seq[Int] scala> fSeq ((0 to 5), (0 to 5)) res0: Seq[Int] = RangeG(0, 3, 12, 15, 21, 24, 30, 33, 42, 45, 51, 54) scala> def fOpt (mx:Option[Int], my:Option[Int]) = for (x <- mx; y <- my if (x+y)%3==0) yield x*10+y fOption: (Option[Int],Option[Int])Option[Int] scala> fOpt (Some(2), Some(4)) res1: Option[Int] = Some(24) scala> fOpt (Some(2), Some(5)) res2: Option[Int] = None scala> fOpt (Some(2), None) res3: Option[Int] = None
で、for 構文で使えるようにする(モナドっぽくする)には、map、flatMap、filter の3つのメソッドを定義すればいいらしいです。
flatMap は bind なので当然必要だとして、map は unit の代替ですね。for を展開していくときに、m2 flatMap (y => unit (x*10+y)) とやる代わりに、m2 map (y => x*10+y) としても、同じ結果が返るので。
ただ filter はちょっと分かりません。for の中の if(guard 条件)のために必要なのだろうけど、これってコレクション系以外のモナドだとあまり意味がないように思います。はて?