简体   繁体   中英

Scala shapeless selection from HList of dependent types problem

I have a type dependent Cf type which stores singletoned string:

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
    }
  }
}

Imaging having another class Dbtest which only stores columns of some HList type:

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

Then I wanted to write some extension methods for my Cf type but there is one restiction: type of the instance on which extension method is going to be called have to be presented in HList of Dbtest instance :

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)

  }
}

Creating instances of Cf and Dbtest instance with some of them inside:

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


I want this to compile because c was specified in the HList:

 c.simplePrint()

And this not to compile because g is not presented in the HList:

g.simplePrint()

Main problem is - I cannot specify implicit Selector type correctly, so my simplePrint() method is not seen by the compiler:

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

Is there a way I can specify selector type correctly?

There is no way to infer N in CfOps(ecf) for specific ecf: C , so N is just some abstract type and there is no implicit evidence C =:= Cf.Aux[N] .

Try to replace definition of CfOps with

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)
}

Then

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM