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

时间:2015-07-29 04:48:15

标签: scala typeclass context-bound

在我的库中,我有三种类型:

T

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

  • 如果类型scala.math.NumericAbelianGroup类型,则它也是T
  • 如果类型AbelianGroupMonoid,它也是AbelianGroup(目前,Monoid扩展T,但不一定是这种情况)
  • 如果类型Monoid是类型为U的向量,类型U是T,则键入Monoid也是AbelianGroup
  • 如果类型T是类型U上的向量,类型U是T,则AbelianGroup也是(Int, Int)

例如,由于Int是Vector over Int,而(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], U : AbelianGroup] : AbelianGroup[T] = ... } 也是AbelianGroup。

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

(Int, Int)

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

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

  2. AbelianGroup

  3. 为解决这种歧义,我修改了Monoid伴随类,以包含从Numeric(以及可直接转换为/*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], 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], U : AbelianGroup] : AbelianGroup[T] = ... } 的其他类型)的直接转换。

    AbelianGroup

    然而,这有点令人不满意,因为它基本上违反了DRY委托人。当我为Numeric添加新的实现时,我将不得不在两个伴随对象中实现转换,就像我为 #define O_WRONLY 01 #define O_APPEND 02000 int main(void) { // fd is an indentifier for the file that we are going to work with int fd; // We open the file with the write or append mode, so you will // have to create the file testfile.txt in the current directory. fd = open("jobby.txt", O_WRONLY|O_APPEND, 0); if(fd < 0) return 2; char str[10]= ""; char buf1[] = "Please type username and hit Enter: "; write(1, buf1, sizeof(buf1)); read (0, str, 10); write(fd,str, sizeof(str)); char str1[10]= ""; char buf2[] = "Please type in a password and hit Enter: "; write(1, buf2, sizeof(buf2)); read (0, str1, 10); write(fd,str1, sizeof(str)); char str2[10]= ""; char buf4[] = "Please re-enter password and hit Enter: "; write(1, buf4, sizeof(buf4)); read (0, str2, 10); write(fd,str2, sizeof(str)); if(sizeof(str1)==sizeof(str2)) { char buf5[] = "\n password match: "; write(1, buf5, sizeof(buf5)); } else { char buf6[] = "\n password mismatch: "; write(1, buf6, sizeof(buf6)); } 和OtherTypeX等所做的那样。所以,我觉得我是&#39;在某个地方转了一圈。

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

1 个答案:

答案 0 :(得分:0)

你可以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], U : Monoid] : Monoid[T] = ...
}

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