如何修改此库设计,以便Scala推断出正确的构建器隐式参数?

时间:2016-02-28 13:28:43

标签: scala type-inference scala-collections

下面我有一个我正在处理的库的简化版本。我在scala集合库的CanBuildFrom特性之后对此进行了建模,因为我的要求类似。但是,我无法推断出在所有情况下都要使用的正确构建器。在下面的示例中,如果我明确指定要使用的构建器,则所有方法都有效,但是对于"模糊的隐式值"我得到了编译错误。当我没有指定构建器时,即使orderedMultiSignalBuilder似乎应该严格比multiSignalBuilder更具体。我做错了什么?

trait Builder[-F, -SourceElement[X] <: Element[X]] {
  type Result[X] <: MultiSignal[X]
  type TargetElement[X] >: SourceElement[X]
  def mapElement[T, U](element : SourceElement[T], value : U) : TargetElement[U] = {
    throw new Exception() //not implemented yet
  }
  def buildNew[T, U](element : TargetElement[T]) : Result[U] = {
    throw new Exception() //not implemented yet
  }
}

object Builder {
  implicit object multiSignalBuilder extends Builder[MultiSignal[Any], Element] {
    type Result[X] = MultiSignal[X]
  }
  implicit def orderedMultiSignalBuilder[P] = new Builder[OrderedMultiSignal[Any] { type Position = P }, ({type λ[α] = OrderedElement[α, P]})#λ]() {
    type Result[X] = OrderedMultiSignal[X] { type Position = P }
  }
}

trait Element[+T] {
  val value : T
}

trait OrderedElement[+T, +P] extends Element[T] {
}

trait MultiSignal[+T] {
  type ElementType[+X] <: Element[X]

  val element : ElementType[T]

  def map[U](f : T => U) (implicit builder : Builder[this.type, ElementType]) : builder.Result[U] =
    builder.buildNew(builder.mapElement(element, f(element.value)))
}

trait OrderedMultiSignal[+T] extends MultiSignal[T] {
  type Position
  type ElementType[+X] = OrderedElement[X, Position]
}

object multiSignal extends MultiSignal[Int] {
  type ElementType[+X] = Element[X]
  val element = new Element[Int] { val value = 0 }
}

object orderedMultiSignal extends OrderedMultiSignal[Int] {
  type Position = Int
  val element = new OrderedElement[Int, Int] { val value = 0 }
}

object Test {
  multiSignal.map(_.toString)
  orderedMultiSignal.map(_.toString) (Builder.multiSignalBuilder)
  val result : OrderedMultiSignal[String] { type Position = Int } = orderedMultiSignal.map(_.toString) (Builder.orderedMultiSignalBuilder[Int])

  //Next line gets compile error: ambiguous implicit values error
  val result2 : OrderedMultiSignal[String] { type Position = Int } = orderedMultiSignal.map(_.toString)

}

1 个答案:

答案 0 :(得分:2)

trait Builder[-F, -Source[X] <: Element[X]] { type Result[X] <: MultiSignal[X] } trait Element[+T] { val value: T } trait OrderedElement[+T, +P] extends Element[T] object MultiSignal { implicit object builder extends Builder[MultiSignal[Any], Element] { type Result[X] = MultiSignal[X] } } trait MultiSignal[+T] { type Elem[X] <: Element[X] def map[U](f: T => U)(implicit b: Builder[this.type, Elem]): b.Result[U] = ??? } object OrderedMultiSignal { implicit def builder[P] = new Builder[OrderedMultiSignal[Any] { type Pos = P }, ({type λ[α] = OrderedElement[α, P]})#λ]() { type Result[X] = OrderedMultiSignal[X] { type Pos = P } } } trait OrderedMultiSignal[+T] extends MultiSignal[T] { type Pos type Elem[X] = OrderedElement[X, Pos] } object multi extends MultiSignal[Int] { type Elem[X] = Element[X] } object ordered extends OrderedMultiSignal[Int] { type Pos = Int } object Test { multi .map(_.toString) ordered.map(_.toString) val res0: MultiSignal [String] = multi .map(_.toString) val res1: OrderedMultiSignal[String] {type Pos=Int} = ordered.map(_.toString) } 中的两个隐式构建器与Scala的推断观点的特殊性不相同 。如果您查看集合中如何定义构建器,您会注意到它们是特定集合类型的伴随对象的一部分。如果将构建器移动到相应的随播类型,则优先级将起作用:

this.type

map中使用Repr对我来说也是错误的。它可以在这里工作,但我认为你应该用Unmet dependency: xscrnsaver QtWebEngine will not be built. 替换它,它是信号的另一个类型成员。