結論とは関係ない流れから解説
この前blog書いたExtendという型クラスに関する話↓
あーたしかに、Haskell(の標準ライブラリ)にBindないなぁー。あれ、でもどこかになかったっけ?
↓
お ekmett/semigroupoids に Bind ある!
https://github.com/ekmett/semigroupoids/blob/v3.0.2/src/Data/Functor/Bind.hs
↓
なんとなくソースコード読む
↓
そういえば、「Bindになるけれど、Monadにならないもの」*1って、(少なくとも現状Scalazを見た限りは)存在しないよなー、そういう意味では、Scalazは無駄に(?)型クラスを細かく分けすぎだよなー
という疑問が、以前からずっとあった
↓
「A 'Map' is not a 'Monad', but it is an instance of 'Bind'」という記述を偶然semigroupoidsで見つける( ゚д゚)!?
https://github.com/ekmett/semigroupoids/blob/v3.0.2/src/Data/Functor/Bind.hs#L448
↓
Scalazで実装してみる
↓
できた!?(((o(*゚▽゚*)o)))
https://github.com/xuwei-k/scalaz/commit/718af600aeefda8dd88c05dd1749b1f594f6eb2e#diff-2
def bind[A, B](fa: Map[K, A])(f: A => Map[K, B]): Map[K, B] = fa.collect{case (k, v) if f(v).isDefinedAt(k) => k -> f(v)(k) }
ちなみに、試しにMonad[({type F[V] = Map[K,V]})#F]にしてみて、無理やり
def point[A](a: => A) = Map.empty[K, A]
もしくは
def point[A](a: => A) = Map.empty[K, A].withDefaultValue(a)
と実装しても、Monadのlawを満たさずに、テストが失敗する!追記:
withDefaultValueは、「applyの動作だけ変えて、getの動作は変えない」のでそのあたり考慮してなかったですね・・・。あと、本当にMapはMonadにならないのか?を考えたら、ちょっとややこしかったので、このtogetterも読んでください
というわけで、理論的にはBindが存在するべき理由は全然説明できないし、曖昧にしか理解できてない(?)ですが
「MapはBindにはなるけれど、Monadにはならない」
という例が1つ見つかったので、一応
「Bindの存在意義*2はある」
と言っていいのではないでしょうか?
本体にpull reqは、あとでするかもしれないし、しないかもしれない*3
他に「Bindにはなるけれど、Monadにはならない」例を知っていたら教えて下さい。
あと、ついでに「Applyにはなるけれど、BindにもApplicativeにもならない」という例とかあるんですかね・・・?
HaskellのZipListはApplicativeになるが、それをstrictなScalaのListに対して定義しようとすると、Applyになる(そしてApplicativeにはなれない)
追記:
そういえば、BindになるけどMonadにならないやつ、UnwriterTもあった URL
2013-06-02 00:23:30 via web