Выражение ограниченного типа F как члена абстрактного типа
Я хочу преобразовать ограниченный F полиморфизм в члены абстрактного типа.
trait FBoundedMovable[Self <: FBoundedMovable[Self]] {
def moveTo(pos: Vect2): Self
}
в
trait Movable { self =>
type Self <: (Movable { type Self = self.Self })
def moveTo(pos: Vect2): Self
}
Все идет нормально.
Давайте определим экземпляр:
case class Ship(pos: Vect2) extends Movable {
type Self = Ship
def moveTo(pos: Vect2) = copy(pos = pos)
}
И попробуйте использовать это:
// [error] found : a.Self
// [error] required: A
def move[A <: Movable](a: A, to: Vect2): A = a.moveTo(to)
F ограниченная версия работает отлично.
def moveF[A <: FBoundedMovable[A]](a: A, to: Vect2): A = a.moveTo(to)
Я знаю, что можно добавить границы типов на сайт определения метода:
def move2[A <: Movable { type Self = A }](a: A, to: Vect2): A = a.moveTo(to)
Но возможно ли указать отношение в объявлении Подвижного признака? Если нет - почему?
Редактировать 1
Я понял, что у меня за проблема.
Допустим, мы хотим объявить, что что-то является единицей в нашем мире.
trait WorldUnit extends Movable with Damageable
Все подразделения являются подвижными и разрушаемыми.
Наши боевые расчеты заботятся только о том, что Movable with Damagable
, Неважно, будет ли это единица или здание.
Однако у нас может быть такой код:
def doCombat(obj: Movable with Damagable) = obj.moveTo(...).takeDamage(...)
def doStuffWithUnit(obj: WorldUnit): WorldUnit = doCombat(obj) // and the type is lost here.
Обречен ли я на F ограниченных типов?
Изменить 2:
На вопрос не отвечает попытка смоделировать F-ограниченный полиморфизм как член типа в Scala - я пробовал это раньше, и он не влияет ни на какой возвращаемый тип, это все еще a.Self.
Изменить 3:
Я нашел http://blog.jessitron.com/2014/02/when-oo-and-fp-meet-mytype-problem.html но проблема все еще не решена.
В основном, когда у вас есть коллекция, и вы хотите выбрать одну:
(collection: Seq[Movable]).collectFirst { m: Movable if m.someCondition => m }
- у вас нет возможности указать границы типа, поэтому компилятор не может доказать, что A#Self =:= A?
1 ответ
Тип-проекции в скале зависят от пути. Быстрый пример
scala> trait A{
| type T
| }
defined trait A
scala> val a = new A{type T = String}
a: A{type T = String} = $anon$1@31198ceb
scala> val b = new A{type T = String}
b: A{type T = String} = $anon$1@236ab296
scala> def f(implicit evidence: A =:= b.T) = null
f: (implicit evidence: =:=[A,b.T])Null
scala> f("asdf":a.T)
<console>:12: error: type mismatch;
found : a.T
(which expands to) String
required: =:=[A,b.T]
(which expands to) =:=[A,String]
f("asdf":a.T)
^
В вашем случае выдает ошибку из-за типа возвращаемого значения. Это справедливо ожидает a.type
но ты вернешься A
, И они не одинаковы.
Причина, по которой они не должны быть одинаковыми:a.type
возвращает тип <: Movable
, Для воображения какое-то число x
менее 100. Метод move
возвращается A
а для воображения это какой-то другой номер y
меньше 100. Нет необходимости, чтобы х было таким же, как у.