5

Ich habe versucht, einen Typ zu definieren, der in Scala einen existentiell höheren Typ akzeptiert.Wie definiere ich einen existenziellen höheren Typ in Scala?

Leider Scalac erlaubt es nicht.

Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

trait H[F[_, _]] 
trait T[A, B] 
val h:H[T] = null 
val e:H[F] forSome { type F[A, B] } = h 

// Exiting paste mode, now interpreting. 

<console>:13: error: type mismatch; 
found : H[T] 
required: H[_[A, B] <: Any] 
Note: T <: Any, but trait H is invariant in type F. 
You may wish to define F as +F instead. (SLS 4.5) 
     val e:H[F] forSome { type F[A, B] } = h 
              ^

Wie könnte ich es umgehen?

Wie könnte ich einen Typ definieren, der mit irgendeinem H übereinstimmt, was auch immer der Typparameter ist?

Update: Ich habe sogar versucht, Scalac auf den existenziellen Typ schließen zu lassen, immer noch nicht glücklich.

Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

trait H[F[_, _]] 
trait T[A, B] 
val h:H[T] = null 
trait T2[A, B] 
val h2:H[T2] = null 
Seq(h, h2) 

// Exiting paste mode, now interpreting. 

<console>:17: error: type mismatch; 
found : H[T] 
required: H[_ >: T2 with T <: Object] 
     Seq(h, h2) 
     ^
<console>:17: error: type mismatch; 
found : H[T2] 
required: H[_ >: T2 with T <: Object] 
     Seq(h, h2) 
      ^
+0

Ich glaube nicht, Sie können. Siehe http://stackoverflow.com/questions/3122398/cant-existential-abstract-over-parameterized-type – sschaef

+0

Hier ist das Seltsame: mach 'H'-Kovariante in 'F' (' Merkmal H [+ F [_, _ ]] ') und auf einmal kompiliert sich folgendes:' val h2: H [Any] = null '. Ja das ist 'Any' genau dort, wo ein Typ ** Konstruktor ** erwartet wird. Wenn jemand weiß, ob es beabsichtigt ist (und wenn ja, was das bedeutet), würde ich es gerne wissen. –

+0

@ RégisJean-Gilles Ich denke, es ist ein Scalac-Bug –

Antwort

0

Wahrscheinlich hat sschaef recht, das ist nicht möglich. Ich weiß nicht, ob die folgende Sie in irgendeiner Weise hilft:

type F[A,B] = X[A,B] forSome { type X[A,B] } // alias 

trait H[F[_, _]] 
trait T[A, B] 
val h: H[T] = null 

val e: H[F] = h.asInstanceOf[H[F]] 
0

Ich fand, dass existentielle höherer kinded Typen in Typmuster geschrieben werden kann (und abgeleitet von dort):

def toExistential[F[_, _]](h: H[F]) = h.asInstanceOf[Any] match { 
    case x: H[_] => x 
} 

> val h = new H[T] {} 
h: H[T] = [email protected] 
> val f = toExistential(h) 
f: H[_] = [email protected] 

Die Cast zu Any scheint notwendig zu sein, aber zumindest kann es in einer Funktion gekapselt werden.

0

Anstelle eines Typ-Parameter Sie ein Typ-Member verwenden:

trait H { 
    type F[_, _] 
} 
Verwandte Themen