The problem with your makeLens is that we want, for example, makeLens[Content]('foo) fail at compile time and this is not possible using the regular Symbol argument. You need additional implicit arguments to track the singleton type for the given name and to prove that it is the name of a member of the case class:
import shapeless._, ops.record.{ Selector, Updater }, record.FieldType class MakeLens[T <: Product] { def apply[K, V, R <: HList](s: Witness.Aux[K])(implicit gen: LabelledGeneric.Aux[T, R], sel: Selector.Aux[R, K, V], upd: Updater.Aux[R, FieldType[K, V], R] ): Lens[T, V] = lens[T] >> s } def makeLens[T <: Product] = new MakeLens[T]
And then:
scala> case class Content(field: Int) defined class Content scala> makeLens[Content]('field) res0: shapeless.Lens[Content,Int] = shapeless.Lens$$anon$6@7d7ec2b0
But makeLens[Content]('foo) will not compile (this is what we want).
For your nestedMapLens you need the same tracking:
import scalaz._, Scalaz._ import shapeless.contrib.scalaz._ case class LensesFor[T <: Product]() { def nestedMapLens[K, V, R <: HList]( outerKey: String, innerKey: Int, s: Witness.Aux[K] )(implicit gen: LabelledGeneric.Aux[T, R], sel: Selector.Aux[R, K, V], upd: Updater.Aux[R, FieldType[K, V], R] ): PLens[Map[String, Map[Int, T]], V] = (lens[T] >> s).asScalaz.partial.compose( PLens.mapVPLens(innerKey) ).compose( PLens.mapVPLens(outerKey) ) }
Please note that I accept build.sbt as follows:
scalaVersion := "2.11.2" libraryDependencies ++= Seq( "com.chuusai" %% "shapeless" % "2.0.0", "org.typelevel" %% "shapeless-scalaz" % "0.3" )
Now let's define an example map and some lenses:
val myMap = Map("foo" -> Map(1 -> Content(13))) val myFoo1Lens = LensesFor[Content].nestedMapLens("foo", 1, 'field) val myBar2Lens = LensesFor[Content].nestedMapLens("bar", 2, 'field)
And then:
scala> myFoo1Lens.get(myMap) res4: Option[Int] = Some(13) scala> myBar2Lens.get(myMap) res5: Option[Int] = None
It’s kind of like “no patterns”, as you are going to get. At first, messy implicit argument lists are scary, but you get used to them pretty quickly, and their role in collecting different bits of evidence about the types you work with becomes quite intuitive after a little practice.