Fight the Future



One Div Zero: Monads are Elephants Part 2の翻訳続き。

Now With More Expression(さらに式を増やしてみる)

Let's kick it up a notch.


val qs = 
   for (n <- ns; o <- os; p <- ps)
      yield n * o * p

This "for" gets expanded into


val qs = ns flatMap {n => 
   os flatMap {o => 
      {ps map {p => n * o * p}}}}

That looks pretty similar to our previous "for." That's because the rule is recursive


for(x1 <- expr1;...x <- expr) 
   yield resultExpr

expands to

expr1 flatMap {x1 => 
   for(...;x <- expr) yield resultExpr

This rule gets applied repeatedly until only one expression remains at which point the map form of expansion is used. Here's how the compiler expands the "val qs = for..." statement (again red italics turns to bold green)


  1. val qs = for (n <- ns; o <- os; p <- ps) yield n * o * p
  2. val qs = ns flatMap {n => for(o <- os; p <- ps) yield n * o * p}
  3. val qs = ns flatMap {n => os flatMap {o => for(p <- ps) yield n * o * p}}
  4. val qs = ns flatMap {n => os flatMap {o => {ps map {p => n * o * p}}}

An Imperative "For"(命令の「for」)

"For" also has an imperative version for the cases where you're only calling a function for its side effects. In it you just drop the yield statement.


val ns = List(1, 2)
val os = List (4, 5)
for (n <- ns; o <- os)  println(n * o)

The expansion rule is much like the yield based version but foreach is used instead of flatMap or map.


ns foreach {n => os foreach {o => println(n * o) }}

Now, you don't have to implement foreach if you don't want to use the imperative form of "for", but foreach is trivial to implement since we already have map.


class M[A] {
   def map[B](f: A=> B) : M[B] = ...
   def flatMap[B](f: A => M[B]) : M[B] = ...
   def foreach[B](f: A=> B) : Unit = {

In other words, foreach can just call map and throw away the results. That might not be the most runtime efficient way of doing things, though, so Scala allows you to define foreach your own way.