- 関数型プログラミング言語Haskell Part29 [転載禁止]©2ch.net
88 :デフォルトの名無しさん[sage]:2015/07/23(木) 10:23:45.67 ID:9NQb4Eqn - >>87
X -> m Y というタイプの関数をたくさん繋げたいという気持ちがあるわけ。mがモナドだとするとき m でラップされた型、たとえば m Int だとか m () だとかを「mという文脈を付与された型」だと思う ことにします。m としては IO や Maybe を考えれば考えやすい。 f :: X -> m Y g :: Y -> m Z みたいなのがあったとき、fの結果の文脈を引き継いでgを計算したいわけ。たとえば m が Maybeならば、fの結果は Nothing かもしれないわけ。IOだったら、実行時環境からIOで ラップされた値を受け取ってるかもしれない。そういうのを受けて g を計算したいわけ。 このとき、>>= があるおかげで (f x) >>= g というのが計算できるわけ。「fのあとにg」というのを素朴に、思いついたままにやろうとすると g ( f x) -- 型が合ってないので illegal だけど、これは m 一個分型がずれてるからダメ。>>= は、一個分の m を吸収して 適用してくれる。だから、「モナドでラップされた値を取り出して適用してくれる」 みたいな言われ方をするけど、まあ、結果としてそう見えるようなうまい定義が されてる。(例えばモナド則なんかがそんなうまい定義の背景にあって、そういうのを どうやって思いついたか説明しようとすると圏論の話しになる。しらんでいい。)
|
- 関数型プログラミング言語Haskell Part29 [転載禁止]©2ch.net
89 :デフォルトの名無しさん[sage]:2015/07/23(木) 10:30:27.22 ID:9NQb4Eqn - >>87
ついで。 IO () みたいに、「中身がない」というか、文脈を持ってるという以外に 意味がないモナド値ってのもある。もっと広く言うと状態系のモナドね。 そういう場合、 f :: X -> m () g :: Y -> m () h :: Z -> m () みたいなのを「つなげたい」場合がある。これは入り口が違うので (>>=) は使えない。 だもんで、(>>) なんてのがある。
|
- 関数型プログラミング言語Haskell Part29 [転載禁止]©2ch.net
91 :デフォルトの名無しさん[sage]:2015/07/23(木) 11:47:48.09 ID:9NQb4Eqn - >>90
「そういうのが作れるならば」あなたのおっしゃるとおり。 具体的に考えてみましょう。 m が Maybe の場合、 extract Nothing は何になりますか
|
- 関数型プログラミング言語Haskell Part29 [転載禁止]©2ch.net
92 :デフォルトの名無しさん[sage]:2015/07/23(木) 11:59:35.34 ID:9NQb4Eqn - >>90
よくいろいろなところで、(>>=) は「モナドから値を取り出して関数に適用する」 と言われたりするけど、unit と join を基礎にしてモナドを作ると、このトリックは 理解しやすい。 参考: ttps://ja.wikibooks.org/wiki/Haskell/%E5%9C%8F%E8%AB%96 要するにMがモナドだとして unit :: a -> M a join :: M (M a) -> M a があったとき (>>=) :: M a -> (a -> M b) -> M b x' >>= f = join ( (fmap f) x' ) となって、実際には fmap f を適用して、ダブった M を一枚剥がして M b の値を返してる。 (つまりモナドの中から値を引っ張りだす、というような事は実際にはやってないわけ)。 実際にはモナドのなかから値を引っ張りだしてないにも関わらず、引っ張りだして 適用したと「プログラマの心の中で」みなしていても整合してるように書けてしまう。 そういううまいルールをどうやって設定するかみたいな話をするために圏論を借りてきてる。 正直、圏論だとかいってもこのレベルの話ならグラフ理論と難しさは変わらん。 (表示的意味論でも圏論を使うけど、そっちは数学がよほど好きでないと厳しい)。
|
- 関数型プログラミング言語Haskell Part29 [転載禁止]©2ch.net
96 :デフォルトの名無しさん[sage]:2015/07/23(木) 14:03:17.98 ID:9NQb4Eqn - >>94
そういう上手いルール、はモナド則です。(Functor則と合わせて機能する)。 >>95 たとえば identity モナドなら extract は存在します。大事なのは「一般には、モナド M に対して extract :: M a -> a が定義できない」ということ。 extract の存在を仮定してると モナドの一般論にはならないわけです。 join :: M(M a) -> M a の存在は、モナドの構成要件の一つだと言って差し支えないと思います。 Mがモナドであるかぎり必ず存在する。 参考:ttp://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Monad.html#v:join (さっき挙げたWikibooksのページには、unit + join でやる流儀と unit + bind でやる流儀の両方が解説されてます。論理的にはどっちで考えても良い。)
|
- 関数型プログラミング言語Haskell Part29 [転載禁止]©2ch.net
100 :デフォルトの名無しさん[sage]:2015/07/23(木) 21:46:55.16 ID:9NQb4Eqn - >>99
たとえば http://d.hatena.ne.jp/itto100pen/20090710 に、モナド則の一部が満たされない例があります。 「普通に定義すれば」モナド則は満たされるというのは、経験的には確かにそういう場面が多いかもしれませんが、 状況が込み入ってくれば、いつか「普通にモナドっぽいものを作ったつもり」なのにモナド則を満たさないものに 遭遇するかもしれません。 >joinがそうであるのにextractがそうでないのはなぜでしょうか? モナドというものがそういうものだからとしか言いようがないですね。 >>93 であなたは >a -> mb の部分がモナドにとって本質的なんだなと思えてきました と書いていましたが、この X -> m Y 型の射をつなげてどうにかするための仕組みが 備わっているものをモナドと呼ぶわけです。うまくこのタイプの射をつなげるためには、 ダブったmをうまく剥がしてくれるものが必要で、それが join なわけです。 さっき挙げたWikibooksのページに、join を使って bind を作ったり、bind を使って join を作る 話が載ってますので、参考になさってください。 一方、あなたが書いてる extract :: M a -> a に相当する仕組みを考える場面は 一応あります。それは、 m X -> Y 型の射をうまくつなげてどうにかしたい場合です。 それは「コモナド」と呼ばれてます。(これを積極的に考える場面もあるらしいのですが 私の勉強が追いついていないのでコモナドについてこれ以上語れることはありません。)
|