monads的通用`implicit`运算符?

时间:2014-06-20 04:11:56

标签: scala operators implicit-conversion typeclass implicit

这是部分编程练习,部分实用。

我想在此示例中构建一个运算符|,以便:

val x: Option[Int] = _
def fail: Nothing = _

val result = x | fail

到目前为止我有这个并且它没有编译:

import language.implicitConversions
import scala.util.{Try, Success, Failure}

trait OrAbleFacilitator[T] {
  def apply[U](t: T, u: => U): U
}

implicit val OptionOrAbleFacilitator = new OrAbleFacilitator[Option[T]] {
  def apply[U, U >: T](t: Option[T], u: => U): U = {
    t match {
      case Some(v) => v
      case _ => u
    }
  }
}

implicit val TryOrAbleFacilitator = new OrAbleFacilitator[Try[T]] {
  def apply[U, U >: T](t: Try[T], u: => U): U = {
    t match {
      case Success(v) => v
      case _ => u
    }
  }
}

implicit class OrAble[T](t: T) {
  def |[U](u: => U)(implicit orFacilitator: OrAbleFacilitator[T, U]): U = {
    orFacilitator(t, u)
  }
}

我做错了什么?

1 个答案:

答案 0 :(得分:2)

我搬了一堆小东西让事情发挥作用。我试图评论我做出更改的大多数地方以使其运行。

import language.implicitConversions
import scala.util.{Try, Success, Failure}

// you need to wrap this all in an object, since you can't have vals at the top level
object Main extends App {
  // you need  to capture in the trait that you are abstracting of a 
  // * → * kind, that is to say it needs to be a type which takes a type
  // as input and returns you a type, such as Option or Try or List..  The thing you are creating an
  // orable for is going to have to be in the shape F[A], not just F,
  // and there is no reason to fix the inner type
  trait OrAbleFacilitator[F[_]] {
    // the first parameter to apply needs to be F[T], and the return type must be a supertype of T
    def apply[T, U >: T](t: F[T], u: => U): U
  }

  implicit val OptionOrAbleFacilitator = new OrAbleFacilitator[Option] {
    // here we need to accept the types for the input and output, adn they must be realted
    def apply[T, U >: T](t: Option[T], u: => U): U = {
      t match {
        case Some(v) => v
        case _ => u
      }
    }
  }

  implicit val TryOrAbleFacilitator = new OrAbleFacilitator[Try] {
    def apply[T, U >: T](t: Try[T], u: => U): U = {
      t match {
        case Success(v) => v
        case _ => u
      }
    }
  }

  // we can't just wrap any old T, it has to be something in the shape
  // F[T] moved the implcit up to where we create the class so that it
  // doesn't cuase us to have an additional parameter list on our |
  // function ( which would prevent us from using it inline )
  implicit class OrAble[F[_], T](t: F[T])(implicit or: OrAbleFacilitator[F]) {
    // the vertical bar | is already a keyword in scala, I used the formal "disjunction" operatior (|) instead.
    def |[U >: T](u: => U): U = {
      or(t, u)
    }
  }

  // and it works:

  val noneint: Option[Int] = None
  val failint: Try[Int] = Failure(new Exception())

  assert((Some(0) : Option[Int]) .|(Some(1)) == 0)
  assert((noneint | 2) == 2)
  assert(((Success(0) : Try[Int]) | 3) == 0)
  assert((failint | 4)  == 4)
}