4

在 Scala 中,重载和隐式参数解析的相互作用似乎使以下代码无法使用。

trait Bijection[A, B] extends Function1[A, B] with Unapply[A, B] { self =>
  def apply(a: A): B
  def unapply(b: B): A
}

sealed trait Unapply[A, B] {
  def unapply(b: B): A
}

object Bijection {
  implicit def biject[A](a: A): Biject[A] = new Biject(a)

  implicit object IntStringBijection extends Bijection[Int, String] {
    override def apply(a: Int): String = a.toString
    override def unapply(b: String): Int = b.toInt
  }
}

sealed class Biject[A](a: A) {
  def as[B](implicit f: Function1[A, B]): B = f(a)
  def as[B](implicit f: Unapply[B, A]): B = f unapply a
}

这里的目标是让 a.as[B] 执行类型安全转换,而不管 Bijection[A,B] 或 Bijection[B,A] 在隐式范围内是否可用。

这不起作用的原因是隐式解析似乎发生在编译器中的重载消歧之后,并且由于 'as' 的两个实现具有相同的结果类型,编译器甚至没有尝试找出适当的隐式是否在可以执行转换的范围内。简而言之,在重载消歧中不使用隐式解析。

我想让'as'重载的原因是为了避免这个库的用户需要在调用站点对双射的“方向”进行编码;显然可以这样实现 Biject:

sealed class Biject[A](a: A) {
  def viaForward[B](implicit f: Function1[A, B]): B = f(a)
  def viaReverse[B](implicit f: Unapply[B, A]): B = f unapply a
}

但这真的很不吸引人,因为它本质上使皮条客变得多余;不妨明确地通过双射,但当然你失去了使所使用的双射根据范围而变化的能力。

这个问题有什么好的解决办法吗?

4

1 回答 1

5

这个怎么样?

trait Bijection[A, B] extends Function1[A, B] with Unapply[A, B] {
  self =>
  def apply(a: A): B

  def unapply(b: B): A
}

sealed trait Unapply[A, B] {
  def unapply(b: B): A
}

object Bijection {
  implicit def biject[A](a: A): Biject[A] = new Biject(a)

  implicit object IntStringBijection extends Bijection[Int, String] {
    override def apply(a: Int): String = a.toString

    override def unapply(b: String): Int = b.toInt
  }
}

sealed class Biject[A](a: A) {
  def as[B](implicit f: Either[Bijection[A, B], Bijection[B, A]]): B = f.fold(_ apply a, _ unapply a)
}

trait EitherLow {
  implicit def left[A, B](implicit a: A): Either[A, B] = Left(a)
}

object Either extends EitherLow {
  implicit def right[A, B](implicit b: B): Either[A, B] = Right(b)
}

import Bijection._
import Either._

1.as[String]
"1".as[Int]
于 2010-10-03T18:09:49.380 回答