#scala #higher-kinded-types
#scala #типы более высокого типа
Вопрос:
Темы различий хорошо представлены во многих местах, но, к сожалению, я не нахожу ни одного места, посвященного этой теме с абстрактными типами.
Затем, пытаясь понять коллекцию, я написал следующее содержимое
trait CollectionOps[ A, C] {
this: C =>
type CC[B] <: BasicColl[B] // Invariant position
def filter(f: A => Boolean): C
def map[B](f: A => B): CC[B] // CC is in a covariant position but declared invariant via abstract type
}
trait BasicColl[ A] extends CollectionOps[A, BasicColl[A]] {
type CC[B] = BasicColl[B] // this is the problem, the equality
// But if i let inequality: type CC[B] <: BasicColl[B]
}
// Do not compile due to previous equality and invariance on CC
trait BasicColl2[ A] extends BasicColl[A] with CollectionOps[A, BasicColl2[A]] {
type CC[B] = BasicColl2[B]
// But if i let the previous inequality i can writte type CC[B] <: BasicColl2[B]
}
trait Test_With_Abstract_Type_Equality {
// Only BasicColl extist
def coll1: BasicColl[Int]
// We have exact type due to equality of CC with BasicColl
def mapped: BasicColl[Double] = coll1.map(_.toDouble)
// But no specialized inhéritence possible
}
trait Test_With_Abstract_Type_Inequality {
def coll1: BasicColl[Int]
// We have abstract type due to inequality of CC with BasicColl
def mappedWithAbstractTypeDef: BasicColl[Int]#CC[Double] = coll1.map(_.toDouble)
// BasicColl2 can exist
def coll2: BasicColl2[Int]
// We have abstract type due to inequality of CC with BasicColl2
def mappedWithAbstractTypeDef2: BasicColl2[Int]#CC[Double] = coll2.map(_.toDouble)
}
Шаблон Scala использует не абстрактный тип, а непосредственно ковариантный параметризованный тип CC следующим образом
trait IterableOnceOps[ A, CC[_], C]
Преимущество ковариации заключается в облегчении смешивания признаков.
Но использование более высокого типа этого типа на уровне параметров типа предотвращает любое расширение класса с более чем 1 параметризованным типом, где использование абстрактного типа позволяет расширить более сложный класс за счет наличия абстрактного типа в качестве вывода. Вот в чем дело, я попробовал это, но я недостаточно уверен в этом риске.
// Redefinition
trait CollectionOps[ A, C] {
this: C =>
type CC[B] <: BasicColl[B] // Invariant position
def filter(f: A => Boolean): C
def map[B](f: A => B): CC[B] // but CC is in a covariant position
}
// Redefinition
trait BasicColl[ A] extends CollectionOps[A, BasicColl[A]]
trait CollectionOpsLocked1[ A, CCC[B] <: BasicColl[B], C] extends CollectionOps[A, C] {
this: C =>
type CC[B] = CCC[B] @uncheckedVariance // this is my question
// If i use CC ONLY in covariant position is there any risk ?
}
trait BasicColl2[ A] extends BasicColl[A] with CollectionOpsLocked1[A, BasicColl2, BasicColl2[A]]
trait BasicColl3[ A] extends BasicColl2[A] with CollectionOpsLocked1[A, BasicColl3, BasicColl3[A]]
trait Test {
def coll1: BasicColl[Int]
def mappedWithAbstractTypeDef: BasicColl[Int]#CC[Double] = coll1.map(_.toDouble)
// BasicColl2 can exist
def coll2: BasicColl2[Int]
def mapped2: BasicColl2[Double] = coll2.map(_.toDouble)
// BasicColl3 can exist
def coll3: BasicColl3[Int]
def mapped3: BasicColl3[Double] = coll3.map(_.toDouble)
}
В более общем случае существует ли какой-либо риск использования @uncheckedVariance
в каком-либо месте, где ковариация / контравариантность являются законными?
Комментарии:
1. «Но использование более высокого типа этого типа на уровне параметров типа предотвращает любое расширение класса с более чем 1 параметризованным типом, где использование абстрактного типа позволяет расширять более сложный класс за счет наличия абстрактного типа в качестве выходного.» — это не совсем так. Ваш
CC[_]
ожидает ровно один параметр типа. Ваш возвращаемый тип применяет ровно один параметр. Даже если вы расширяете свой класс, применяется принцип подстановки Liskov, поэтому вашему расширению также придется ожидать и применять ровно один параметр.2. И если вы хотите использовать что-то с 2 параметрами и исправить один из них самостоятельно … тогда это равносильно использованию kind projector. Таким образом, мощность выражения примерно такая же.