Как вывести 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)

Я понимаю, почему компилятор жалуется (за исключением последней ошибки, которая имеет вводящее в заблуждение описание). Я ищу способ решить эту проблему, а не объяснение, почему все эти подходы не срабатывают. Я записываю их, чтобы проиллюстрировать, в каком направлении я уже искал.

0 ответов

Другие вопросы по тегам