Bindという型クラスの存在意義

結論とは関係ない流れから解説


この前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も読んでください

ScalaのMapはモナドになるのか?



というわけで、理論的にはBindが存在するべき理由は全然説明できないし、曖昧にしか理解できてない(?)ですが
「MapはBindにはなるけれど、Monadにはならない」
という例が1つ見つかったので、一応

「Bindの存在意義*2はある」

と言っていいのではないでしょうか?

本体にpull reqは、あとでするかもしれないし、しないかもしれない*3


他に「Bindにはなるけれど、Monadにはならない」例を知っていたら教えて下さい。
あと、ついでに「Applyにはなるけれど、BindにもApplicativeにもならない」という例とかあるんですかね・・・?
HaskellのZipListはApplicativeになるが、それをstrictなScalaのListに対して定義しようとすると、Applyになる(そしてApplicativeにはなれない)



追記:

*1:もしくは、Applyになるけれど、Applicativeにならないもの

*2:Monadに直接bindメソッドをつけるのではなく、Bindを分けて、 trait Monad[ F[_] ] extends Applicative[F] with Bind[F] という継承関係にする意味

*3:tonymorrisさんが色々いじっているし、そのせいでscalaz-sevenのbranchが壊れている(テスト失敗する)ので、ちょっと落ち着くまで様子見る直った