2015-06-17 24 views
11

Zunächst einmal weiß ich nicht, wie ich mein Problem richtig beschreibe. Dies könnte auch der Grund sein, warum ich keine hilfreichen Ressourcen gefunden habe. Alle Hinweise werden sehr geschätzt.Typklasse und abhängige Typen

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

den obigen Code gegeben, kann ich jetzt definieren und Kette Rules s in dieser Art und Weise:

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

Das funktioniert, wie ich kommt bestimmt aber jetzt ist der schwierige Teil. Ich möchte eine Typklasse Combination vorstellen, die erklärt, wie man zwei Regeln verbindet.

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] 

Diese Typklasse sollte jetzt mit den Operatoren übergeben werden.

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

Das funktioniert immer noch nach einigen Verbesserungen.

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

Aber wenn es komplizierter wird, fallen die Dinge auseinander.

A() and B() and A() 

Wird ein impliziten fehlenden Fehler aus: Combination[and[A, B], A] fehlen. Aber ich möchte, dass es das Ergebnis der impliziten Kombination von and[A, B] (type Result = MyRule) verwendet, die es bereits versteht (Combination[and[A, B]#Result, A]).

Es ist wichtig für mich, die Typinformationen der kombinierten Regeln val x: A and B or A zu behalten, sie zu einem Endergebnis zusammenzufalten ist einfach, aber nicht was ich will.

Das ist so nah wie möglich, aber es kompiliert nicht.

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

zu lösen Welche Version von Scala verwenden Sie und welche IDE? – eliasah

+0

2.11.6 mit IntelliJ, kompiliert über sbt Konsole obwohl – Taig

Antwort

9

Der Grund während der Code nicht kompiliert werden kann, ist, dass die Art von x, erhältlich einen implicit r2: Resolver[A and B] von x und die einzige Art Informationen zu lösen, die auf Anweisung

new c2(x) 

Der Compiler müssen, ist ist r1.R.

Diese Art von Problemen erfordert, dem Compiler mehr Typinformationen zur Verfügung zu stellen und einige implizite Parameter hinzuzufügen. Wenn Sie eine Resolver[A and B] benötigen, können Sie den Typ R nicht verwenden, um eine weitere Resolver[r1.R and C] aufzulösen.

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

Mit diesem verfügbar ist, können Sie die Signatur Ihres c2 umschreiben

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

Beachten Sie, dass die Art alias durch die Verwendung und einen zusätzlichen generischen Parameters Einführung ich die Beziehung zum Ausdruck bringen kann r1.R1 = D, die dann verwendet wird, um die zweite implizite r2

+0

Vielen Dank für das Graben durch meine chaotische Frage & Code. Ich schätze das sehr. Ihre Antwort sieht sehr vielversprechend aus, aber es wird wahrscheinlich eine Weile dauern, bis ich den Kopf eingehüllt habe.Ich habe mich schon immer gefragt, was dieses Aux-Ding ist, als ich über irgendeinen Scalaz oder Shapeless stolperte. – Taig

Verwandte Themen