这是部分编程练习,部分实用。
我想在此示例中构建一个运算符|
,以便:
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)
}
}
我做错了什么?
答案 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)
}