Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 单子的通用“隐式”运算符?_Scala_Operators_Implicit Conversion_Typeclass_Implicit - Fatal编程技术网

Scala 单子的通用“隐式”运算符?

Scala 单子的通用“隐式”运算符?,scala,operators,implicit-conversion,typeclass,implicit,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:

这部分是编程练习,部分是实践

在本例中,我希望构建一个操作符
|
,以便:

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)
  }
}

我做错了什么?

为了让事情顺利进行,我移动了一堆小东西。我试着对大多数地方进行评论,我做了一些更改,以使其运行

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)
}