Как вывести Fbound параметризованного типа?
У меня есть f-связанный тип и другие типы, которые зависят от него. Я пытаюсь объявить их так, чтобы не требовалось явно указывать fbound для операций. Подробности в примере
object WhatIWant {
sealed trait FBound[F <: FBound[F]]
sealed trait Dep[F <: FBound[F]]
final case class Holder[F <: FBound[F]](name : String, dep : Dep[F])
final class SimpleBound extends FBound[SimpleBound]
final case class SimpleDep(data : Int) extends Dep[SimpleBound]
object Usage {
def extract(holder : Holder[SimpleBound]) : Int =
holder.dep.data
def enclose(dep : SimpleDep) : Unit = {
val holder = Holder("sample", dep)
}
}
object DoNotWant {
def extract(holder : Holder[SimpleBound]) : Int =
holder.dep.asInstanceOf[SimpleDep].data // explicit type specification
def enclose(dep : SimpleDep) : Unit = {
val holder = Holder[SimpleBound]("sample", dep) // explicit type specification
}
}
}
Компилятор выдает ошибки, как и ожидалось:
TypeParam.scala:13: error: value data is not a member of param.WhatIWant.Dep[param.WhatIWant.SimpleBound]
holder.dep.data
Это прекрасно имеет смысл. Не все возможно Dep[SimpleBound]
реализации являются SimpleDep
(а компилятор слишком туп sealed
модификатор для рассмотрения)
Тогда я попробовал другой подход:
object WhatITry {
sealed trait FBound[F <: FBound[F]] {
type FDep <: Dep[F]
}
sealed trait Dep[F <: FBound[F]]
final case class Holder[F <: FBound[F]](name : String, dep : F#FDep)
final class SimpleBound extends FBound[SimpleBound] {
override type FDep = SimpleDep
}
final case class SimpleDep(data : Int) extends Dep[SimpleBound]
object Usage {
def extract(holder : Holder[SimpleBound]) : Int =
holder.dep.data
def enclose(dep : SimpleDep) : Unit = {
val holder = Holder("sample", dep)
}
}
}
Это тоже не хорошо:
TypeParam.scala:47: error: type mismatch;
found : dep.type (with underlying type param.WhatITry.SimpleDep)
required: ?#FDep
Note that SimpleDep extends Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
val holder = Holder("sample", dep)
Я пробовал больше подходов:
объект TrySelfType {запечатанная черта FBound [F <: FBound [F]] {this: F => type FDep <: Dep [F]} запечатанная черта Dep [F <: FBound [F]] {this: F# FDep => } Класс конечного случая Holder[F <: FBound [F]] (имя: String, dep: Dep [F])
final class SimpleBound extends FBound[SimpleBound] {
override type FDep = SimpleDep
}
final case class SimpleDep(data : Int) extends Dep[SimpleBound]
object Usage {
def extract(holder : Holder[SimpleBound]) : Int =
holder.dep.data
def enclose(dep : SimpleDep) : Unit = {
val holder = Holder("sample", dep)
}
}
}
object TryAbstract {
sealed trait FBound[F <: FBound[F]] { this : F =>
type FDep <: Dep.TPE[F]
}
object FBound {
type Any = FBound[F] forSome {type F <: FBound[F]}
}
sealed trait Dep {
type MyF <: FBound.Any
}
object Dep {
type TPE[F <: FBound[F]] = Dep { type MyF <: F }
}
final case class Holder[F <: FBound[F]](name : String, dep : F#FDep)
final class SimpleBound extends FBound[SimpleBound] {
override type FDep = SimpleDep
}
final case class SimpleDep(data : Int) extends Dep {
override type MyF = SimpleBound
}
object Usage {
def extract(holder : Holder[SimpleBound]) : Int =
holder.dep.data
def enclose(dep : SimpleDep) : Unit = {
val holder = Holder("sample", dep)
}
}
}
object TryWith {
sealed trait FBound[F <: FBound[F]] {
type FDep <: Dep[F]
}
sealed trait Dep[F <: FBound[F]]
object Dep {
type TPE[F <: FBound[F]] = Dep[F] with F#FDep
}
final case class Holder[F <: FBound[F]](name : String, dep : Dep.TPE[F])
final class SimpleBound extends FBound[SimpleBound] {
override type FDep = SimpleDep
}
final case class SimpleDep(data : Int) extends Dep[SimpleBound]
object Usage {
def extract(holder : Holder[SimpleBound]) : Int =
holder.dep.data
def enclose(dep : SimpleDep) : Unit = {
val holder = Holder("sample", dep)
}
}
}
object TryAbstractExtra {
sealed trait FBound[F <: FBound[F]] { this : F =>
type FDep <: Dep.TPE[F]
}
object FBound {
type Any = FBound[F] forSome {type F <: FBound[F]}
}
sealed trait Dep {
type MyF <: FBound.Any
}
object Dep {
type TPE[F <: FBound[F]] = Dep { type MyF <: F }
}
final case class Holder[F <: FBound[F]](name : String, dep : F#FDep)
def holder(name : String, dep : Dep) = Holder[dep.MyF](name, dep)
final class SimpleBound extends FBound[SimpleBound] {
override type FDep = SimpleDep
}
final case class SimpleDep(data : Int) extends Dep {
override type MyF = SimpleBound
}
object Usage {
def extract(holder : Holder[SimpleBound]) : Int =
holder.dep.data
def enclose(dep : SimpleDep) : Unit = {
val hld = holder("sample", dep)
}
}
}
Но они также потерпели неудачу:
TypeParam.scala:66: error: value data is not a member of param.TrySelfType.Dep[param.TrySelfType.SimpleBound]
holder.dep.data
^
TypeParam.scala:103: error: type mismatch;
found : dep.type (with underlying type param.TryAbstract.SimpleDep)
required: ?#FDep
Note that SimpleDep extends Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
val holder = Holder("sample", dep)
^
TypeParam.scala:128: error: type mismatch;
found : dep.type (with underlying type param.TryWith.SimpleDep)
required: param.TryWith.Dep.TPE[?]
(which expands to) param.TryWith.Dep[?] with ?#FDep
val holder = Holder("sample", dep)
^
TypeParam.scala:149: error: type arguments [dep.MyF] do not conform to method apply's type parameter bounds [F <: param.TryAbstractExtra.FBound[F]]
def holder(name : String, dep : Dep) = Holder[dep.MyF](name, dep)
Я понимаю, почему компилятор жалуется (за исключением последней ошибки, которая имеет вводящее в заблуждение описание). Я ищу способ решить эту проблему, а не объяснение, почему все эти подходы не срабатывают. Я записываю их, чтобы проиллюстрировать, в каком направлении я уже искал.