JavaのコンテナクラスっぽいやつをMonadに仕立て上げ、モナド則を満たす

「[redis.clients.jedis.Response<T> を Functor, Monad に仕立て上げる](http://qiita.com/zaneli@github/items/62c4d126adef2429e217)」の補足記事。
モナドに仕立て上げたつもりがモナド則を満たせてなかった？

### モナド則を満たせているか検証

```scala
scala> import scalaz.Scalaz._
scala> import redis.clients.jedis.Response
scala> import com.zaneli.redis.jedis.responseMonad
scala> val m = 10.point[Response]
scala> def f(x: Int): Response[Int] = (x * 10).point[Response]
scala> def g(x: Int): Response[Int] = (x + 1).point[Response]

scala> 10.point[Response].flatMap(f) == f(10)
res1: Boolean = false

scala> m.flatMap(_.point[Response]) == m
res2: Boolean = false

scala> m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))
res3: Boolean = false
```

あれれ…？
と思ったけど、それもそのはず、そもそもJavaの[redis.clients.jedis.Response](https://github.com/xetorthio/jedis/blob/1ae8379816ef020420b07ee802cc0c38e177c9d7/src/main/java/redis/clients/jedis/Response.java)が `equals` を実装していない。

```scala
scala> 10.point[Response] == 10.point[Response]
res4: Boolean = false
```

こういう場合どうするのがいいんだろう…。とりあえず `scalaz.Equal` を使ってみる。

### scalaz.Equal の導入

```scala
package com.zaneli.redis

import redis.clients.jedis.{Builder, Response}
import redis.clients.jedis.exceptions.JedisDataException

import scalaz.{Equal, Monad}

package object jedis {

  implicit val responseMonad = new Monad[Response] {
    override def point[A](a: => A): Response[A] = {
      val r = new Response(new Builder[A] {
        override def build(o: scala.Any): A = o.asInstanceOf[A]
      })
      r.set(a)
      r
    }

    override def bind[A, B](fa: Response[A])(f: A => Response[B]): Response[B] = {
      val r = new Response[B](new Builder[B] {
        override def build(o: scala.Any): B = f(o.asInstanceOf[Response[A]].get).get
      })
      r.set(fa)
      r
    }
  }

  implicit def responseEqual[A]: Equal[Response[A]] = new Equal[Response[A]] {
    override def equal(a1: Response[A], a2: Response[A]): Boolean = {
      try {
        a1.get == a2.get
      } catch {
        case _: JedisDataException => false
      }
    }
  }
}
```

これにより `===` で中身の値を比較することができる。

```scala
scala> import com.zaneli.redis.jedis.responseEqual

scala> 10.point[Response].flatMap(f) === f(10)
res5: Boolean = true

scala> m.flatMap(_.point[Response]) === m
res6: Boolean = true

scala> m.flatMap(f).flatMap(g) === m.flatMap(x => f(x).flatMap(g))
res7: Boolean = true
```

### 疑問は残る…

~~うーむ、しかし果たしてこれでいいのか。
まず、 `==` が `false` な場合に `===` が `true` となる挙動には問題はないのだろうか。
また、モナド則を満たしていないものをモナドインスタンスにすると、モナド則を満たしていることを前提にした処理が思わぬところで想定通り挙動しないという認識だが、`==` での一致を前提としていれば結局今回の対応ではモナド則を満たせたことにならないのではないか。
Javaのコンテナクラスっぽいやつ?(値を保持する入れ物クラスっぽいやつ)をモナドにするというのが、そもそも悪手なんだろうか。
中身の値を使いたいだけなら、モナドインスタンスにせずに独自に `flatMap` とか必要なメソッドだけ実装するほうが無難なんだろうか…。~~

### 追記

[`MonadLaw`](https://github.com/scalaz/scalaz/blob/122e5f9dfc3fbe9189d1f817e703c78047fbb3ef/core/src/main/scala/scalaz/Monad.scala#L76) や [`BindLaw`](https://github.com/scalaz/scalaz/blob/122e5f9dfc3fbe9189d1f817e703c78047fbb3ef/core/src/main/scala/scalaz/Bind.scala#L56) のメソッドが `implicit FA: Equal[F[A]]` を取るので、今回実装した方針で概ね間違っていなさそう？

```scala
scala> import scalaz.Scalaz._
scala> import redis.clients.jedis.Response
scala> import com.zaneli.redis.jedis._
scala> val m = 10.point[Response]
scala> def f(x: Int): Response[Int] = (x * 10).point[Response]
scala> def g(x: Int): Response[Int] = (x + 1).point[Response]

scala> responseMonad.monadLaw.rightIdentity(m)
res1: Boolean = true

scala> responseMonad.monadLaw.leftIdentity(10, f)
res2: Boolean = true

scala> responseMonad.monadLaw.associativeBind(m, f, g)
res3: Boolean = true
```