如何解决 Scala 中重载解析的限制?

发布于 2024-09-26 02:03:39 字数 1197 浏览 0 评论 0原文

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

但这确实没有吸引力,因为它本质上使皮条客变得多余;人们也可以显式地传递双射,但是这样一来,您当然就失去了使所使用的双射根据范围而变化的能力。

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

In Scala, the interaction of overloading and implicit argument resolution seem to make it impossible to make the following code usable.

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
}

The goal here is for a.as[B] to perform a typesafe conversion irrespective of whether a Bijection[A,B] or a Bijection[B,A] is available in implicit scope.

The reason that this doesn't work is that implicit resolution appears to take place after overload disambiguation in the compiler, and since both implementations of 'as' have the same result type, the compiler doesn't even get around to attempting to find out whether an appropriate implicit is in scope that can perform the conversion. In short, implicit resolution is not used in overload disambiguation.

The reason I want to have 'as' overloaded is to avoid the need for the user of this library to need to encode the "direction" of the bijection at the call site; obviously one could implement Biject as this:

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
}

but this is really unappealing because it essentially makes the pimp superfluous; one might as well explicitly pass the bijection, but then of course you lose the ability to have the bijection that is used vary based upon the scope.

Is there any good solution to this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

汐鸠 2024-10-03 02:03:39

这怎么样?

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]

How's this?

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]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文