11

I have the next code

trait A { val id: Int } 
case class B(id: Int) extends A 
case class C(id: Int, name: String) extends A

i want to define common lens for all class hierarchy:

import shapeless._
import lens._ 
val idLens = lens[A] >> 'id

But i get error: could not find implicit value for parameter mkLens: shapeless.MkFieldLens[A,Symbol with shapeless.tag.Tagged[String("id")]]

Is it possible to define lens for all children of trait A?

lito
  • 989
  • 8
  • 21
  • You have to provide an implicit MkFieldLens[A, K]. The problem is I don't know how to specify K (Symbol with shapeless.tag.Tagged[String("id")]). Anyone solved this? – Giovanni Caporaletti Feb 19 '16 at 14:27

1 Answers1

4

shapeless doesn't provide an implicit conversion from A to Record. You could define LabelledGeneric[A] to provide the corresponding record type conversion:

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

trait A { val id: Int }
case class B(id: Int) extends A
case class C(id: Int, name: String) extends A

implicit val lgenA = new LabelledGeneric[A] {
  type Repr = Record.`'id -> Int`.T
  def to(a: A) : Repr = ('id ->> a.id) :: HNil
  def from(r: Repr): A = new A { val id = r('id) }
}

val idLens = lens[A] >> 'id

val b = B(7)
println(idLens.get(b)) // 7
devkat
  • 1,624
  • 14
  • 15
  • @devkat Thanks for the useful answer. I follow you code, and try to change the `id` value by `set` function as below: `println(idLens.set(b)(8))` , which is expecting to get a new instance of `B` back. However, it doesn't. It show some strange characters like `Test2$$anon$1$$anon$2@6276ae34`. Would please help to work out this? Thanks in advance. – user5698801 May 10 '18 at 02:39