モナド(プログラミング)単語

プログラミングニオケルモナド

4.6千文字の記事
掲示板をみる(15)
  • twitter
  • facebook
  • はてな
  • LINE
  • ほめる(4)
  •  
  •  
  •  
  •  
  • その他

プログラミングに出てくるモナドとはよくわからないなにか、あるいはHaskellの危険地帯である。

まとめ

  • モナドには種類があり、種類ごとに意味が異なる。「モナド」とひとくくりに理解することはできない。
  • 各種モナドは、それぞれのAPIを理解できれば他のライブラリと同様に扱えばいい。
  • よってこの記事は駄である。

記事の概要

この記事を開いたあなたはきっと、「今度こそよくわからないモナドをきちんとわかるように解説してくれるページが現れたかもしれない(たぶん違うんだろうな)」と思ってページを開いたことと思う。

すまない。この投げやりな冒頭にさぞ手抜き立て逃げだと憤ったことであろう。しかし、モナドの説明に深入りしたあなたは、あちこちを調べて回った挙句、この冒頭に憤ったことも忘れてこう思うかもしれない。もうよくわからないなにかでいいや、と。

以下の記事を読んで「なんだ簡単じゃないか、脅かしやがって」と思えたなら、この記事の説明がよその記事よりは良かったということいやむしろ読者の理解を褒め称えるべきであり、「もうよくわからないなにかでいいや」と思ったらこの冒頭は間違っていなかったことになる。

なお、最近では関数型プログラミングモナドの理解は必要ないという意見が流を占めつつあるように思える。当記事の初稿編集者も同意見で、モナドに属する個々のクラスAPIドキュメントを理解することが必要かつ十分だと思うので引き返すなら今のうちである。

モナドに言レベルでのサポートがあるのはHaskellくらいなので、他のプログラミング言語モナドを知る必要性はさらに薄いといえる。

なお、この記事はやたら長くなっているが、それでもモナド理論の入り口くらいまでで、実践するところまではカバーしていない。いくらやっても入り口から先に進むことが出来ないから、少々手間でも入り口くらいには立ってみたい。そういう人向けの記事でありたいけどこめんwwwww

引き返す

モナドの理解には関わらない以上、たとえ以下の記事の内容がこの記事よりも優れていたとしても以下のリンクには進まないのが賢明な判断というものである。

説明開始とみせかけて更に引き止める

モナドに対しての関わり方には以下の3通りがある。

  1. モナドを使う
  2. モナドを作る
  3. モナドが何であるかを理解する

モナドを使うのが的であれば、今からでも遅くはない。ブラウザの戻るボタンを押して使いたいモナドAPIドキュメントを読んだほうが良い。

モナドクラスを設計するのが的であれば、そんなことにこだわるより、便利なクラスになるように心がけた方が良い。必要であればそれは自然モナドになるし、必要がなければそうはならない。きっとそんなものだと思う。

モナドが何であるかを理解するという問題については、そもそもそれが可かというところから検討しなければいけないかもしれない。

ちまたにあふれる説明が分かりにくい理由

長い上に愚痴っぽいので過去のリビジョンに格納しました。

説明

モナドの概要

いろいろな人がいろいろな解説を試みており、モナドとはである(だれも全貌を把握できない)とか、モナドとはモナドである(モナドと同じ性質を持つものはモナドしかないという意味で、必ずしも説明を放棄しているわけではないと思われる。)といったいかがわしい説明まで出る始末である。

プログラミングにおけるモナドとは、プログラミングにおける一つの定的手法(デザインパターン)が、HakellでいうところのクラスScalaでいうところのtrait(英語特性という意味でJavaの抽クラスが多重継承可になったようなもの)、Javaでいうところのインターフェース提供されるものだといえる。

もうこの時点で、モナドの意味を考えるという行為に疑問を抱かねばならない。デザインパターンに「意味」をめたりするだろうか。仮にめているとして、同じ種類の意味をモナドめようとしているだろうか。

モナドには種類があり、個々のモナドごとに違った意味を持っている。個々のモナドの意味を通り越して、全てのモナドに共通の意味をめようとすることが不幸の始まりなのである。

ラムダ式

モナドるのに高階関数は欠かせない。そしてそれを表現する手段としてラムダ式の表現方法はないとかえって煩雑になる。ラムダ式の書き方はプログラミング言語により多少差があるが、ここでは

f(x) = x2 + x + 1のとき、f = λ x → x2 + x + 1

という表記法をとることにする。

を意識せざるを得ないのだが、どう表記しよう。ジェネリクスとかタプルとか。

xをインスタンスに持つXに対応するAモナド

unitA(x): A[X]

関数

unitA: X → A[X]

と書くことにする。

モナドの説明

まず、モナドとはMaybeモナドStateモナドなどの総称であり、たとえばMaybeモナドという個々のモナド自体が、Maybeモナドモナド則を満たすものの総称である。つまりモナドは総称の総称ということになる。

モナド則を満たす一番単純でわかりやすい実装は、上記リンク先でも取り上げられているデータを格納したである。実際たいていの実装は何らかの形で内部にモナドの元になるデータを保持している。

前提なのか定義なのかで混乱しやすい。

また、値の定まっていない変数なのか、代入されて値が固定されているのかが字面からは判断しづらいことも混乱に拍をかけているように思える。

2つの関数

たとえば仮にAモナドというものを考える。

任意の値xに対応する(1対1とは限らない)AモナドAxが存在する。1対1とは限らないので、この記法は問題があるどころかこの記法でついた先入観から脱却するのが困難になるのだがとりあえずをつぶることにする。

unit()

ここで関数unit(x)を考える。Haskellのreturnに相当。モナドごとに異なる関数なので、再代入により変数名を使いまわしたりしない関数型プログラミングの考え方を参考にAモナドunit()unitAと書くことにする。

unitA(x) = Ax (Haskellだとretrun x == Ax)という定義になる。

とりあえず、x を A というの中に入れるイメージでよい。(モナドにするときに情報が維持される場合以外に、情報が増える場合と減る場合があり、モデルではその点については誤解が生じやすい。ちゃんと通用するのはIdentityやMaybe(Option)モナドなど、xとAxに一対一対応がある時くらいで、モナドの種類によってはすぐに限界を露呈し、かえって理解の妨げになる。後で補足する。)

x

unitA()

x

= Ax

flatMap()

もう一つflatMap(これもモナドごとに異なる関数である)という高階関数を考える。Haskellの>>=に相当する。

モデルはいけないと思いつつも、イメージをつかむ方法が他にないので、モデルで説明すると、

f(x) = Ayのとき、

flatMapA(Ax, f) = Ay (HaskellだとAx >>= f == Ay) = unitA(y)

x

mapA(f)

f(x) = Ay

=

y

flattenA()

y

の中でxに関数fを適用すると、の中に、に入ったyが出てくる。いうなればAAyの状態である。flatMapではAAyの状態をAyにする。AAyをAyにすることをflatにする(flatten)と呼ぶ。納得行かなくてもそう呼ぶ慣習になっているので。

map(これもモナドごとに異なる関数(ry)という関数名前の元になっている。

g(x) = y のとき

mapA(Ax, g) = Ay

Ax(たりうるものの集合)からAy(たりうるものの集合)への写像(map)になっているので、こう呼ぶ。

mapしてflattenするという考え方から、flatMapという関数名で扱う言が多い(Haskellはそうではない)。

unit()同様とりあえず把握するためにモデルで説明しているが、このモデルで考えるとかえって混乱するモナドが多いので、あくまでもとりあえずの理解のためと割りきっておくこと。

AAyをAyにできるのだから、Ayをyにすることも出来そうだが、それができることは保されない。

また説明の都合上map関数を定義したが、map関数が定義できることは保されていない。flatMapから合成できるとか何とか。

モデルだとAxからxを取り出せそうに見えるし、実際取り出せるモナドが多いのだが、モナドの性質としては保されない。後述の定数モナドを参照のこと。

にわとりとたまご

unit()flatMap()もそういう関数が「ある」というのではなく、モナド則を満たすようにunit()flatMap()を「定義する」のである。unit()ともかくモデルflatMap()unit(x)で得られるモナドには通用するものの、それでは説明できない実装の方が多い。モナド則さえ満たせればモデル実装である必要は全くない。

モナドという単で、上記で言うAxのようなデータすことも多いが、データのみではモナドになることはできない。unit()flatMap()を組み合わせてはじめてモナドと呼べるのである。

Haksellでのモナドの意味

宣言型プログラミングにおいて手続きの順番は定できない。順番を定したければ関数適用の順番によってするしかないのである。

文脈

モナドは文脈を持った計算という表現をされることが多々ある。

強いて言うならば、モナドにするときに情報が増えたり減ったりするが、情報が増えたこと、減ったことを気にせずに、計算を続けたいという希望えることができる。しかし、値を取り出そうとすると最終的にはその情報の増減には向き合わねばならない。

モナド合成

モナドの闇である。

ABx と BAxは一致しない。

モナド変換子(monad transformer)。

たとえば、List<Optional<T>>とOptional<List<T>>を考えれば分かるように、前者は個々の要素について値がある場合とない場合があるが、後者は要素全てに値があるか、要素が存在しないかの2通りしかない。

解決策として以下のようなものが提唱されているらしいが、普及はしていないようだ。

子記事

関連項目

この記事を編集する
流行語100

掲示板

おすすめトレンド

急上昇ワード改

最終更新:2021/12/03(金) 23:00

ほめられた記事

最終更新:2021/12/03(金) 23:00

ウォッチリストに追加しました!

すでにウォッチリストに
入っています。

OK

追加に失敗しました。

OK

追加にはログインが必要です。

           

ほめた!

すでにほめています。

すでにほめています。

ほめるを取消しました。

OK

ほめるに失敗しました。

OK

ほめるの取消しに失敗しました。

OK

ほめるにはログインが必要です。

タグ編集にはログインが必要です。

タグ編集には利用規約の同意が必要です。

TOP