В 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
}
но это действительно непривлекательно, потому что это делает сутенера лишним; с тем же успехом можно явно пропустить биекцию, но тогда, конечно, вы потеряете возможность изменять используемую биекцию в зависимости от объема.
Есть ли хорошее решение этой проблемы?