scala.util.Try の Monad Transformer

自分で使うつもりも、pull reqするつもりもないけど、なんとなく思いついたので、EitherTとかOptionTとか見ながら真似して作った。そもそも必要なのか自分でもよくわからない。そもそもTryがモナドじゃない?としたら、Monad Transformarと呼ぶには語弊がある。あと、それぞれのメソッドが正しい定義なのかも自信ない。型クラスのインスタンスもまだ全部定義してない

https://github.com/xuwei-k/scalaz-contrib/blob/39c89544e8d7a9/scala210/main/scala/TryT.scala

package scalaz.contrib
package std

import scala.util.control.NonFatal
import scala.util.{Try, Success, Failure}
import scalaz._

final case class TryT[F[+_], +T](run: F[Try[T]]){ self =>

  def isFailure(implicit F: Functor[F]): F[Boolean] = mapT(_.isFailure)

  def isSuccess(implicit F: Functor[F]): F[Boolean] = mapT(_.isSuccess)

  def getOrElse[U >: T](default: => U)(implicit F: Functor[F]): F[U] = mapT(_.getOrElse(default))

  def orElse[U >: T](a: => TryT[F, U])(implicit F: Monad[F]): TryT[F, U] = TryT(
    F.bind(run) {
      case Failure(_) => a.run
      case x @ Success(_) => F.point(x)
    }
  )

  def get(implicit F: Functor[F]): F[T] = mapT(_.get)

  def foreach[U](f: T => U)(implicit F: Each[F]): Unit = F.each(run)(_ foreach f)

  def flatMap[U](f: T => TryT[F, U])(implicit F: Monad[F]): TryT[F, U] = TryT[F, U](
    F.bind(self.run) {
      case e @ Failure(_) => F.point(e.asInstanceOf[Try[U]])
      case Success(z) => f(z).run
    }
  )

  def flatMapF[U](f: T => F[U])(implicit F: Monad[F]): TryT[F, U] = TryT[F, U](
    F.bind(self.run) {
      case e @ Failure(_) => F.point(e.asInstanceOf[Try[U]])
      case Success(z) => F.map(f(z))(Success(_))
    }
  )

  def map[U](f: T => U)(implicit F: Functor[F]): TryT[F, U] = TryT(mapT(_ map f))

  def filter(p: T => Boolean)(implicit F: Functor[F]): TryT[F, T] = TryT(mapT(_.filter(p)))

  def recoverWith[U >: T](f: PartialFunction[Throwable, TryT[F, U]])(implicit F: Monad[F]): TryT[F, U] = TryT(
    F.bind(self.run) {
      case x @ Failure(e) =>
        try {
          if (f isDefinedAt e) f(e).run else F.point(x)
        } catch {
          case NonFatal(e) => F.point(Failure(e))
        }
      case z @ Success(_) => F.point(z)
    }
  )

  def recover[U >: T](f: PartialFunction[Throwable, U])(implicit F: Functor[F]): TryT[F, U] =
    TryT(mapT(_.recover(f)))

  def toOption(implicit F: Functor[F]): OptionT[F, T] =
    OptionT.optionT(F.map(run)(_.toOption))

  def failed(implicit F: Functor[F]): TryT[F, Throwable] = TryT(mapT(_.failed))

  def transform[U](s: T => TryT[F, U], f: Throwable => TryT[F, U])(implicit F: Monad[F]): TryT[F, U] = TryT[F, U](
    F.bind(self.run) {
      case Failure(e) => f(e).run
      case Success(z) => s(z).run
    }
  )

  private[this] def mapT[B](f: Try[T] => B)(implicit F: Functor[F]): F[B] = F.map(run)(f)
}