Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

モナドについて調べていく(13)

One Div Zero: Monads are Elephants Part 2の翻訳。
今回からパート2のエントリです。
衝撃的ですが、これはパート4まであるようです。
またこのBlogの著者はScala Blogのグループに属しているそうです。
どうりでわかりやすいわけだ。。。

In part 1, I introduced Scala's monads through the parable of the blind men and the elephant.

パート1では盲目の男たちと象の寓話を通じてScalaモナドを紹介しました。


Normally we're supposed to take the view that each blind man doesn't come close to understanding what an elephant is, but I presented the alternative view that if you heard all the blind men describe their experience then you'd quickly build a surprisingly good understanding of elephants.

ふつうこの話は、男たちがそれぞれ象がどんなものか理解が深まっていないという観点で使います。
しかし別の観点を示しました。もし全員の経験を聞いていたなら象への驚くほどよい理解を素早く構築できるだろうと。


In part 2 I'm going to poke at the beast some more by exploring Scala's monad related syntactic sugar: "for comprehensions."

パート2ではその動物をもう少しついてみるつもりです。シンタックスシュガーに関連するScalaモナドを説明します。「for内包表記」です。

A Little "For"(もう少し「for」を)

A very simple "for" looks like this
とても単純な「for」は次のようなものです。

val ns = List(1, 2)
val qs = for (n <- ns) yield n * 2
assert (qs == List(2, 4))

The "for" can be read as "for [each] n [in] ns yield n * 2." It looks like a loop, but it's not. This is our old friend map in disguise.

「for」は「for [each] n [in] ns yield n * 2」と読み替えられます。ループのようですがそうではありません。
これは偽装した我々の古い友人、mapです。

val qs = ns map {n => n * 2}

The rule here is simple

ここでのルールは単純です。

for (x <- expr) yield resultExpr

Expands to
を展開すると

expr map {x => resultExpr}

And as a reminder, that's equivalent to

そして覚えておいてほしいのですが、これは次と等価になります。

expr flatMap {x => unit(resultExpr)}

More "For"(さらに「for」を)


One expression in a "for" isn't terribly interesting. Let's add some more

「for」における1つの式はあまり興味深いものではありません。もう少し付け加えてみましょう。

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

This "for" could be read "for [each] n [in] ns [and each] o [in] os yield n * o. This form of "for" looks a bit like nested loops but it's just a bit of map and flatMap.

この「for」は「"for [each] n [in] ns [and each] o [in] os yield n * o」と読み替えられます。
この「for」の形は少しネストしたループに見えますが、どちらかというとmapとflatMapです。

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

It's worth while to spend a moment understanding why this works. Here's how it gets computed (red italics gets turned into bold green):

なぜこれが動作するのか理解するために時間を費やすことはムダではありません。
どのように計算されるか見てみましょう(イタリック体の赤字が太字の緑字に変換されます)。

  1. val qs = ns flatMap {n => os map {o => n * o }}
  2. val qs = ns flatMap {n => List(n * 4, n * 5)}
  3. val qs = List(1 * 4, 1 * 5, 2 * 4, 2 * 5)