Scala бесформенный выбор из HList задачи зависимых типов - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть тип Cf, зависящий от типа, в котором хранится строка с одним тоном:

trait Cf {
  type Name <: String with Singleton
  def value: Name
}
object Cf {

  type Aux[A <: String with Singleton] = Cf { type Name = A }


  def apply(name: String): Aux[name.type] = { 
    val w = name.witness
    new Cf {
      override type Name = w.T
      override def value: Name = w.value
    }
  }
}

Отображение с другим классом Dbtest, в котором хранятся только столбцы некоторого типа HList:

class Dbtest[T <: HList](val columns: T)

Тогда я хотел написать несколько методов расширения для моего типа Cf, но есть одно ограничение: тип экземпляра, для которого будет вызываться метод расширения, должен быть представлен в HList экземпляра Dbtest:

object Ops {
  implicit class CfOps[C, N <: String with Singleton, T <: HList](ecf: C)
  (
    implicit 
      db: Dbtest[T]
    , ev: C =:= Cf.Aux[N]
    , selector: Selector[T, C]

  ) {

    private val cf = selector(db.columns)
    def simplePrint(): Unit = println(cf.value)

  }
}

Создание экземпляров Cf и Dbtest экземпляр с некоторыми из них внутри:

object Test extends App {
  val c = Cf("c")
  val b = Cf("b")
  val g = Cf("g")
  implicit val db = new Dbtest(c :: b :: HNil)
  ...


Я хочу, чтобы это компилировалось, потому что c было указано в HList:

 c.simplePrint()

И это не компилируется, потому что g не представлен в HList:

g.simplePrint()

Основная проблема - я не могу правильно указать неявный тип селектора, поэтому мой метод simplePrint() не виден компилятором:

value simplePrint is not a member of Cf{type Name = String("c")}

Можно ли правильно указать тип селектора?

1 Ответ

1 голос
/ 13 февраля 2020

Нет способа вывести N в CfOps(ecf) для указания c ecf: C, поэтому N - это просто какой-то абстрактный тип, и не существует неявного доказательства C =:= Cf.Aux[N].

Попробуйте заменить определение CfOps на

implicit class CfOps[N <: String with Singleton, T <: HList](ecf: Cf.Aux[N])(
  implicit
  db: Dbtest[T],
  selector: Selector[T, Cf.Aux[N]]
) {
  private val cf = selector(db.columns)
  def simplePrint(): Unit = println(cf.value)
}

Тогда

import Ops._
c.simplePrint() // compiles
//g.simplePrint() // doesn't compile
...