2015-06-17 66 views
11

首先,我不知道如何正確標記我的問題。這也可能是我沒有找到有用資源的原因。任何提示都非常感謝。類型類和相關類型

trait Context[T] 
{ 
    self => 

    trait Rule 
    { 
     def apply(value: T): Boolean 
    } 

    implicit class RichRule[A <: Rule](a: A) 
    { 
     def and[B <: Rule](b: B): and[A, B] = self.and(a, b) 
     def or[B <: Rule](b: B): or[A, B] = self.or(a, b) 
    } 

    sealed trait Group[A <: Rule, B <: Rule] extends Rule 
    { 
     def a: A 

     def b: B 

     override def apply(value: T) = ??? 
    } 

    case class and[A <: Rule, B <: Rule](a: A, b: B) extends Group[A, B] 
    case class or[A <: Rule, B <: Rule](a: A, b: B) extends Group[A, B] 
} 

鑑於上面的代碼中,我能以這種方式現在定義和鏈Rules S:

new Context[String] 
{ 
    class MyRule extends Rule 
    { 
     override def apply(value: String) = true 
    } 

    case class A() extends MyRule 
    case class B() extends MyRule 

    val x1: A and B or A = A() and B() or A() 
} 

這個工程,我打算,但現在到了棘手的部分。我想介紹一個Type Type Combination,它解釋瞭如何加入兩條規則。

trait Combination[-A <: Rule, -B <: Rule] 
{ 
    type Result <: Rule 

    def combine(a: A, b: B): Result 
} 
trait AndCombination[-A <: Rule, -B <: Rule] extends Combination[A, B] 
trait OrCombination[-A <: Rule, -B <: Rule] extends Combination[A, B] 

此類型類現在應該與操作符一起傳遞。

implicit class RichRule[A <: Rule](a: A) 
{ 
    def and[B <: Rule](b: B)(implicit c: AndCombination[A, B]): and[A, B] = ??? 
    def or[B <: Rule](b: B)(implicit c: OrCombination[A, B]): or[A, B] = self.or(a, b) 
} 

哪些經過一些調整後仍在工作。

implicit val c1 = new Combination[MyRule, MyRule] 
{ 
    type Result = MyRule 

    def combine(a: A, b: B): MyRule = a 
} 

val x: A and B = A() and B() 

但是,如果它變得更加複雜,事情就會崩潰。

A() and B() and A() 

會引發一個隱含的缺失錯誤:缺少Combination[and[A, B], A]。但我希望它使用它已知道如何處理(Combination[and[A, B]#Result, A])的and[A, B]type Result = MyRule)的隱式組合的結果。

對我來說,保留組合規則val x: A and B or A的類型信息非常重要,將它們摺疊在一起以最終結果類型很容易,但不是我想要的。

雖然這樣儘可能地接近,但編譯失敗。

trait Context[T] 
{ 
    self => 

    trait Rule 

    trait Value extends Rule 

    trait Group[A <: Rule, B <: Rule] extends Rule 
    { 
     def a: A 

     def b: B 

     implicit val resolver: Resolver[_ <: Group[A, B]] 
    } 

    case class and[A <: Rule, B <: Rule](a: A, b: B)(implicit val resolver: Resolver[and[A, B]]) extends Group[A, B] 

    implicit class RichRule[A <: Rule](a: A) 
    { 
     def and[B <: Rule](b: B)(implicit resolver: Resolver[and[A, B]]) = self.and[A, B](a, b) 
    } 

    trait Resolver[-A <: Rule] 
    { 
     type R <: Value 

     def resolve(a: A): R 
    } 
} 

object O extends Context[String] 
{ 
    implicit val c1 = new Resolver[A and A] 
    { 
     override type R = A 

     override def resolve(a: O.and[A, A]) = ??? 
    } 

    implicit def c2[A <: Value, B <: Value, C <: Value](implicit r1: Resolver[A and B]) = new Resolver[A and B and C] 
    { 
     override type R = C 

     override def resolve(a: A and B and C): C = 
     { 
      val x: r1.R = r1.resolve(a.a) 
      new c2(x) 
      ??? 
     } 
    } 

    class c2[A <: Value, B <: Value](val a: A)(implicit r2: Resolver[A and B]) extends Resolver[A and B] 
    { 
     override type R = B 

     override def resolve(a: O.and[A, B]) = a.b 
    } 

    case class A() extends Value 

    val x: A and A and A = A() and A() and A() 
} 
+0

您正在使用什麼版本的Scala以及哪些IDE? – eliasah

+0

2.11.6使用IntelliJ,通過sbt控制檯編譯雖然 – Taig

回答

9

,而你的代碼不能編譯的原因是,在指令

new c2(x) 

編譯器需要解決從x可用implicit r2: Resolver[A and B],唯一的類型信息的x的類型,是r1.R

這類問題需要向編譯器提供更多的類型信息並添加一些隱式參數。當您需要Resolver[A and B]時,不能使用其R類型來解析另一個Resolver[r1.R and C]

type ResolverAux[-A<:Rule,B] = Resolver[A] { type R = B } 

有了這個可用,你可以重寫你的C2的簽名

implicit def c2[A <: Value, B <: Value, C <: Value,D<:Value](implicit r1: ResolverAux[A and B,D], r2:Resolver[D and C]):Resolver[A and B and C] = new Resolver[A and B and C] 
    { 
    override type R = C 

    override def resolve(a: A and B and C): C = 
    { 
     val x: r1.R = r1.resolve(a.a) 
     new c2[r1.R,C](x) 
     ??? 
    } 
    } 

注意,使用類型別名,並引入附加的泛型參數,我可以表達的關係r1.R1 = D然後將其用於解決第二個隱含的問題r2

+0

非常感謝您通過我雜亂的問題和代碼進行挖掘。我真的很感激。你的答案看起來很有希望,但它可能會花費我一段時間來圍繞它。我一直在想,當我偶然發現一些Scalaz或沒有形狀的時候,這個Aux是什麼。 – Taig