2016-02-28 13 views
0

下面我有一個正在處理的庫的簡化版本。我在scala集合庫的CanBuildFrom特性之後對此進行了建模,因爲我的需求是相似的。但是,我無法完全推斷出所有情況下使用正確的生成器。在下面的示例中,如果我明確指定了要使用的構建器,但所有方法都能正常工作,但是當我沒有指定構建器時,雖然看起來orderedMultiSignalBuilder應該是更嚴格的,但我得到了「模棱兩可的隱式值」的編譯錯誤具體比multiSignalBuilder。我做錯了什麼?如何修改此庫設計,以便Scala能夠推斷出正確的構建器隱式參數?

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) 

} 
+0

您是否嘗試過將低優先級隱式放入'對象構建器'會擴展的特性? –

回答

2

你兩個object Builder隱含的建設者是從視圖Scala的推理點特異性不同。如果你看看如何在集合中定義構建器,你會注意到它們是特定集合類型的伴隨對象的一部分。如果您移動的建設者到各自的伴侶類型,優先級工作:

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

使用this.typemap看起來還我錯了。它在這裏工作,但我認爲你應該用另一種類型的信號替代Repr

相關問題