Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
654 views
in Technique[技术] by (71.8m points)

typeclass - In scala 2.13, why is it sometimes impossible to summon type class explicitly? - Part 2

This is a follow up question of In scala 2.13, why is it sometimes impossible to summon type class explicitly?:

The following code can compile properly:

  import shapeless._
  import record._
  import syntax.singleton._

  val book =
    ("author" ->> "Benjamin Pierce") ::
      ("title" ->> "Types and Programming Languages") ::
      ("id" ->> 262162091) ::
      ("price" ->> 44.11) ::
      HNil

  val v1 = book.values

  assert(v1.head == "Benjamin Pierce")

  case class HasValues[T <: HList: TypeTag](v: T) {

//    def vs(implicit v: Values[T]) = v // doesn't work
    def vs(implicit v: Values[T]): Values.Aux[T, v.Out] = v // works
  }

  val _vs = HasValues(book).vs

  val v2 = book.values(_vs)

  assert(v2.head == "Benjamin Pierce")

While the following code, which is syntactically identical in both compile time and run time, failed the compilation:

  import shapeless._
  import record._
  import syntax.singleton._

  val book =
    ("author" ->> "Benjamin Pierce") ::
      ("title" ->> "Types and Programming Languages") ::
      ("id" ->> 262162091) ::
      ("price" ->> 44.11) ::
      HNil

  val v1 = book.values

  assert(v1.head == "Benjamin Pierce")

  case class HasValues[T <: HList: TypeTag](v: T) {

    type TT = T
  }

  val hv = HasValues(book)

  val _vs = implicitly[Values[hv.TT]]
  val _vs2: Values.Aux[hv.TT, _vs.Out] = _vs

  val v2 = book.values(_vs2)

  assert(v2.head == "Benjamin Pierce")

resut:

[Error] /home/peng/git-spike/scalaspike/common/src/test/scala/com/tribbloids/spike/shapeless_spike/RecordProblem2.scala:41: could not find implicit value for parameter c: shapeless.ops.hlist.IsHCons[com.tribbloids.spike.shapeless_spike.RecordProblem2._vs2.Out]
one error found

In addition, the following line seems to be very boilerplate-y. Ideally I think the compiler should be able to figure out the refinement on itself, considering that this is totally an upcast:

  val _vs = implicitly[Values[hv.TT]]
  val _vs2: Values.Aux[hv.TT, _vs.Out] = _vs

Why the second one failed the compilation, and furthermore, how to get rid of that boilerplate duck type declaration? (Of course, without modifying the signature of the class HasValues)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

implicitly can corrupt type refinements. Use shapeless.the instead.

The code

val hv = HasValues(book)

val _vs = the[Values[hv.TT]]
val _vs2: Values.Aux[hv.TT, _vs.Out] = _vs

val v2 = book.values(_vs2)

assert(v2.head == "Benjamin Pierce")

compiles.

https://typelevel.org/blog/2014/01/18/implicitly_existential.html

Scala compiler expand types

Also

val hv = HasValues(book)

val _vs2 = the[Values[hv.TT]]

val v2 = book.values(_vs2)

assert(v2.head == "Benjamin Pierce")

and

val hv = HasValues(book)

val v2 = book.values

assert(v2.head == "Benjamin Pierce")

compile.

Also notice that you can replace

def vs(implicit v: Values[T]): Values.Aux[T, v.Out] = v

with

def vs(implicit v: Values[T]): v.type = v

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...