Возврат зависимого от пути типа
Как я могу разработать метод, который возвращает зависимый от пути тип? В следующем примере я намеренно хочу Vertex
быть зависимым от пути Tree
так, что запрещено смешивать вершины между деревьями (и это только пример):
trait Tree {
trait Vertex
def root: Vertex
def addChild(parent: Vertex): Vertex
}
trait TreeFactory { def make: Tree }
Теперь следующее не может быть построено:
def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = {
val t = f.make
var sq = IndexedSeq(t.root)
var m = Map.empty[t.Vertex, t.Vertex]
for( i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = t.addChild(p)
m += c -> p
sq :+= c
}
(t, m)
}
Потому что, очевидно, карта, которую я возвращаю, не должна иметь ключей и значений типа Tree#Vertex
но из зависимой от пути вершины...
error: type mismatch;
found : scala.collection.immutable.Map[t.Vertex,t.Vertex]
required: Map[Tree#Vertex,Tree#Vertex]
Note: t.Vertex <: Tree#Vertex, but trait Map is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Tree#Vertex`. (SLS 3.2.10)
(t, m)
^
Если я попытаюсь разделить создание дерева и построение родительско-дочерней карты:
def test(t: Tree): Map[t.Vertex, t.Vertex] = {
var sq = IndexedSeq(t.root)
var m = Map.empty[t.Vertex, t.Vertex]
for (i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = t.addChild(p)
m += c -> p
sq :+= c
}
m
}
Это терпит неудачу по другой причине: "error: illegal dependent method type"
3 ответа
Мой извращенный ум придумал это. Я надеюсь, что есть более элегантное решение:
trait Gagaism {
val tree: Tree
val map: Map[tree.Vertex, tree.Vertex]
}
def test(f: TreeFactory) = new Gagaism {
val tree = f.make
val map = {
var sq = IndexedSeq(tree.root)
var m = Map.empty[tree.Vertex, tree.Vertex]
for (i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = tree.addChild(p)
m += c -> p
sq :+= c
}
m
}
}
Вы можете включить экспериментальную поддержку для зависимых типов методов с -Xexperimental -Ydependent-method-types
, Я думаю.
Я недостаточно хорошо понимаю систему типов, чтобы объяснить, почему ваша первая попытка не работает, но я обычно следую этой схеме (с ограниченными членами абстрактного типа), которая компилируется. Было бы неплохо увидеть реализации Tree
а также TreeFactory
чтобы быть более уверенным, хотя.
package trees
trait Tree {
trait Vertex
type V <: Vertex
def root: V
def addChild(parent: V): V
}
trait TreeFactory { def make : Tree }
object Test {
def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = {
val t = f.make
var sq = IndexedSeq(t.root)
var m = Map.empty[t.Vertex, t.Vertex]
for (i <- 1 to 100) {
val p = sq(util.Random.nextInt(sq.size))
val c = t.addChild(p)
m += c -> p
sq :+= c
}
(t, m)
}
}