Fight the Future

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

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

One Div Zero: Monads are Elephants Part 3の翻訳続き。
ついにモナド則まできました。

Functors and Monads, Alive, Alive Oh(ファンクターとモナドはまだまだ続く)


As you may have guessed by now all monads are functors so they must follow the functor laws. In fact, the functor laws can be deduced from the monad laws. It's just that the functor laws are so simple that it's easier to get a handle on them and see why they should be true.

もう想像したかもしれませんが、すべてのモナドはファンクターです。それゆえモナドはファンクターの法則に従います。
実際、ファンクターの法則はモナド則から演繹されます。ファンクターの法則は単純なのでそれを理解しなぜ真になるのか理解することは簡単です。


As a reminder, a Scala monad has both map and flatMap methods with the following signatures

思い出してほしいのですが、Scalaモナドは次のシグネチャでmapとflatMapの両方のメソッドを持っています。

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

Additionally, the laws I present here will be based on "unit." "unit" stands for a single argument constructor or factory with the following signature

その上、ここで示した法則は「unit」に基づいています。「unit」は単一引数のコンストラクタかファクトリを表します。
次のようなシグネチャです。

def unit[A](x:A):M[A] = ...

"unit" shouldn't be taken as the literal name of a function or method unless you want it to be. Scala doesn't specify or use it but it's an important part of monads.

「unit」はそうしたいと思わない限り関数やメソッドのリテラル名を引数に取るべきではありません。
Scalaはそれを条件づけたり使ったりしませんが、これはモナドの重要な部分です。


Any function that satisfies this signature and behaves according to the monad laws will do. Normally it's handy to create a monad M as a case class or with a companion object with an appropriate apply(x:A):M[A] method so that the expression M(x) behaves as unit(x).

このシグネチャを満たしモナド則に従って振る舞うあらゆる関数はそう動作します。
通常、式M(x)がunit(x)として振る舞うようにモナドMを適切なapply(x:A):M[A]メソッドを持つケースクラスや随行オブジェクトとして作成するのは便利です。

The Functor/Monad Connection Law: The Zeroth Law(ファンクター/モナド結合法則:0番目の法則)


In the very first installment of this series I introduced a relationship

このシリーズの一番初めの前置きで関連をこのように紹介しました。

  • FM1. m map f ≡ m flatMap {x => unit(f(x))}

This law doesn't do much for us alone, but it does create a connection between three concepts: unit, map, and flatMap.

この法則は単独ではあまり意味を成しませんが、3つのコンセプトunitとmap、flatMapの結びつきを作り出します。


This law can be expressed using "for" notation pretty nicely

この法則は「for」表記法を使ってかなりうまく表現されるでしょう。

  • FM1a. for (x <- m) yield f(x) ≡ for (x <- m; y <- unit(f(x))) yield y

Flatten Revisited(flattenふたたび)


In the very first article I mentioned the concept of "flatten" or "join" as something that converts a monad of type M[M[A]] into M[A], but didn't describe it formally. In that article I said that flatMap is a map followed by a flatten.

一番最初の記事で「flatten」または「join」のコンセプトをM[M[A]]野茂などをM[A]に変換するものとして言及しましたが、正しく記述していません。
その記事ではflatMapがflattenに従ったmapだと言いました。

  • FL1. m flatMap f ≡ flatten(m map f)

This leads to a very simple definition of flatten

これは非常に単純なflattenの定義を導きます。

  • flatten(m map identity) ≡ m flatMap identity // substitute identity for f
  • FL1a. flatten(m) ≡ m flatMap identity // by F1

So flattening m is the same as flatMapping m with the identity function. I won't use the flatten laws in this article as flatten isn't required by Scala but it's a nice concept to keep in your back pocket when flatMap seems too abstract.

ゆえにmをflattenすることはmをidentity関数とともにflatMapすることと同じです。Scalaではflattenは必要でないのでこの記事ではflattenの法則を使いたくありませんが、flatMapが抽象化され過ぎであるときのためにflatternは知っておくとよい概念です。