Собирайте экземпляры через LiftAll

Я пытаюсь описать типы, которые содержит класс case.

import shapeless._
import shapeless.ops.hlist.LiftAll

trait Desc[T] {
  def description: String
}

case class Foo(f: Int)
object Foo {
  implicit val description: Desc[Foo] = new Desc[Foo] { val description = "foo" }
}

case class SomeCaseClass(f: Foo)

val gen = Generic[SomeCaseClass]
val lifted = implicitly[LiftAll[Desc, gen.Repr]].instances.toList

Дает мне

could not find implicit value for parameter toTraversableAux: shapeless.ops.hlist.ToTraversable.Aux[shapeless.ops.hlist.LiftAll[Playground.this.Desc,Playground.this.gen.Repr]#Out,List,Lub]
not enough arguments for method toList: (implicit toTraversableAux: shapeless.ops.hlist.ToTraversable.Aux[shapeless.ops.hlist.LiftAll[Playground.this.Desc,Playground.this.gen.Repr]#Out,List,Lub])toTraversableAux.Out.
Unspecified value parameter toTraversableAux.

Скастите здесь: https://scastie.scala-lang.org/bXu71pMQQzCqrrsahVBkWA


person Reactormonk    schedule 10.01.2018    source источник


Ответы (1)


Когда вы вызываете неявный экземпляр с помощью implicitly[LiftAll[Desc, gen.Repr]], зависимый тип Out от LiftAll теряется, поэтому компилятор не знает, какой именно тип instances вернет.

Чтобы обойти эту проблему, большинство классов типов в Shapeless определяют метод apply в своем сопутствующем объекте, который сохраняет всю информацию о зависимых типах. Это причина того, что вы можете осмысленно использовать gen.Repr после вызова val gen = Generic[SomeCaseClass]. Однако по какой-то причине LiftAll.apply не был реализован таким образом. Таким образом, у вас есть возможность реализовать свой собственный implicitly или, поскольку вы все равно используете Shapeless, использовать его the, который должен быть лучше implicitly.

scala> def impl[T <: AnyRef](implicit ev: T): ev.type = ev
impl: [T <: AnyRef](implicit ev: T)ev.type

scala> impl[LiftAll[Desc, gen.Repr]].instances.toList
res1: List[Desc[Foo]] = List(Foo$$anon$1@40b3708a)

scala> the[LiftAll[Desc, gen.Repr]].instances.toList
res2: List[Desc[Foo]] = List(Foo$$anon$1@40b3708a)

Здесь вы можете увидеть разницу в предполагаемых типах, которые отображает REPL:

scala> impl[LiftAll[Desc, gen.Repr]]
res3: LiftAll.Aux[Desc,Foo :: HNil,Desc[Foo] :: HNil] = shapeless.ops.hlist$LiftAll$$anon$206@384d060c

scala> implicitly[LiftAll[Desc, gen.Repr]]
res4: LiftAll[Desc,gen.Repr] = shapeless.ops.hlist$LiftAll$$anon$206@30787774
person Jasper-M    schedule 11.01.2018