top page > computer > haskell > web_lecture > for_programmer > not_monad_applicative_draft.html
更新日:
文責: 重城良国

モナドではないアプリカティブ (下書き)

(工事中 0%)

はじめに

この記事はきれいにまとめられたら独立した記事にする。

ZipList的なものもモナドから導ける

たとえば値3つのタプルは以下のようにモナドにできる。

return x = (x, x, x)
(x, y, z) >>= f = let
(x', _, _) = f x
(_, y', _) = f y
(_, _, z') = f z in
(x', y', z')

ZipListはモナドにならないアプリカティブの代表的なものだが、それはリストのリストにおいて要素数がバラバラであるということの結果であり、あまり本質的なことではない。無限リストを考えればZipListはモナドになるし、要素数が一定であるようなリストであればやはりモナドになる。

モナド則を満たさないinsaneなものながら、型クラスMonadのインスタンスとしてZipListを定義することができる。そしてその定義を利用して型クラスApplicativeなsaneなインスタンスとして定義することが可能だ。

ならば本質的にモナドでないアプリカティブとは

これを考えるときにはモナドとアプリカティブの違いをできるだけ単純に抽出することが役に立つだろう。モナドとアプリカティブの違いは以下の関数に要約できる。

つまり関数tupなら定義できるけれど関数joinは定義できないような例を考えればいい。これが思ったより難しい。f aとf bをマージすることとf (f a)を平坦にすることとは2個のfという構造をマージするという点では共通しているからだ。

関数tupのほうでしかできないことは何かということだ。f aとf bをマージするときに一度f (f (a, b))のような形にしてそれを関数joinで平坦にするようなやりかたではうまくいかないような関数tupの例を考えればいい。f (f (a, b))のようにしたときの外側のfはf a由来の構造だ。もしもf a -> f b -> f (a, b)がf bの構造の一部を必要としているようなときに、f aがNothing的な構造であり「なかみがない」ようなときf (f (a, b))において、f bの構造部分もまた消えてしまう。

つまりf aが「なかみがない」ような値であることがあり、tup :: f a -> f b -> f (a, b)の結果がf bの構造に依存するような例を考えれば、モナドにはできないアプリカティブを作ることができる。そのようにして作ったのがnma1.hsだ。とりあえずまだリファクタリングやより本質的な部分の抽出はしていない。また、いちおうQuickCheckでモノイダル則の確認はしたが、きちんとした証明はしていない。とりあえずのたたきだいだ。

モノイダル則の確認は以下のようにした。

ghci nma1.hs
*Main> quickCheck (prop_monoidal_left :: List Int -> Bool)
...
*Main> quickCheck (prop_monoidal_right :: List Int -> Bool)
...
*Main> quickCheck (prop_monoidal_assoc :: List Int -> List Int -> List Int -> Bool)
...

QuickCheckのためにRandomやBoundedのインスタンスにいちおうしたが、あまりよくないインスタンス定義だ。

最もシンプルな例

nma2.hs

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics