加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何避免具有多个Type Class关系的模糊转换链?

发布时间:2020-12-16 19:14:22 所属栏目:安全 来源:网络整理
导读:在我的库中,我有三个类型类: trait Monoid[T] { val zero : T def sum(x : T,y : T) : T}trait AbelianGroup[T] extends Monoid[T] { def inverse(x : T) : T def difference(x : T,y : T) : T}//represents types that are represents lists with a fixed
在我的库中,我有三个类型类:

trait Monoid[T] {
  val zero : T
  def sum(x : T,y : T) : T
}

trait AbelianGroup[T] extends Monoid[T] {
  def inverse(x : T) : T
  def difference(x : T,y : T) : T
}

//represents types that are represents lists with a fixed number of elements,such as
//the tuple type (Int,Int)
trait Vector[T,U] {
  ...
}

在以下条件下,这些类型类可以相互转换:

>如果类型T是scala.math.Numeric类型,则它也是AbelianGroup.
>如果类型T是AbelianGroup,它也是一个Monoid(目前,AbelianGroup扩展了Monoid,但不一定是这种情况)
>如果类型T是类型U上的向量,并且类型U是Monoid,则类型T也是Monoid.
>如果类型T是类型U上的向量,类型U是AbelianGroup,则T也是AbelianGroup.

例如,因为(Int,Int)是Int over Int类型,而Int是AbelianGroup,所以(Int,Int)也是AbelianGroup.

这些关系和其他关系很容易在伴侣类中实现,如下所示:

object Monoid {
  implicit def fromAbelianGroup[T : AbelianGroup] : Monoid[T] = implicitly[AbelianGroup[T]]
  implicit def fromVector[T : Vector[T,U],U : Monoid] : Monid[T] = ...
}

object AbelianGroup {
  implicit def fromNumeric[T : Numeric] : AbelianGroup[T] = ...
  implicit def fromOtherTypeX[T : ...] : AbelianGroup[T]
  ...
  implicit def fromVector[T : Vector[T,U : AbelianGroup] : AbelianGroup[T] = ...
}

这很好用,直到你尝试使用类似元组类型(Int,Int)之类的东西作为Monoid.编译器找到两种方法来获得这种类型的Monoid类型类对象:

> Monoid.fromAbelianGroup(AbelianGroup.fromVector(Vector.from2Tuple,
AbelianGroup.fromNumeric))
> Monoid.fromVector(Vector.from2Tuple,
Monid.fromAbelianGroup(AbelianGroup.fromNumeric))

为了解决这种歧义,我修改了Monoid伴随类,以包含从Numeric(以及可直接转换为AbelianGroup的其他类型)的直接转换.

/*revised*/
object Monoid {
  //implicit def fromAbelianGroup[T : AbelianGroup] : Monoid[T] = implicitly[AbelianGroup[T]]
  implicit def fromNumeric[T : Numeric] : Monoid[T] = ... //<-- redundant
  implicit def fromOtherTypeX[T : ...] : AbelianGroup[T] = ... //<-- redundant
  ...
  implicit def fromVector[T : Vector[T,U : Monoid] : Monid[T] = ...
}

object AbelianGroup {
  implicit def fromNumeric[T : Numeric] : AbelianGroup[T] = ...
  implicit def fromOtherTypeX[T : ...] : AbelianGroup[T] = ...
  ...
  implicit def fromVector[T : Vector[T,U : AbelianGroup] : AbelianGroup[T] = ...
}

然而,这有点令人不满意,因为它基本上违反了DRY委托人.当我为AbelianGroups添加新的实现时,我将不得不在两个伴随对象中实现转换,就像我为Numeric和OtherTypeX做的那样,等等.所以,我觉得我在某个地方做了一个错误的转向.

有没有办法修改我的代码以避免这种冗余并解决编译时模糊错误?这种情况下的最佳做法是什么?

解决方法

你可以 move the implicits for which you want to have lower priority into a supertype of the companion object:

trait LowPriorityMonoidImplicits {
  implicit def fromVector[T : Vector[T,U : Monoid] : Monoid[T] = ...
}

object Monoid extends LowPriorityMonoidImplicits  {
  implicit def fromAbelianGroup[T : AbelianGroup] : Monoid[T] = implicitly[AbelianGroup[T]]
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读