Pregunta

Basado en:

import shapeless._

case class Content(field: Int)
lens[Content] >> 'field

Estoy tratando de hacer un lente-la creación de método, algo así:

def makeLens[T <: Product](s: Symbol) = lens[T] >> s

Pero parece que no es evidente.Es posible hacer?

Si no, el resultado final estoy tratando de lograr es un método genérico para la actualización de anidado Mapas con el caso de la clase de contenido, por ejemplo:

import scalaz._
import Scalaz._
import PLens._
import shapeless._
import shapeless.contrib.scalaz._

def nestedMapLens[R, T <: Product](outerKey: String, innerKey: Int, f: Symbol) =
  ~((lens[T] >> f).asScalaz) compose mapVPLens(innerKey) compose mapVPLens(outerKey)

No puedo ir a trabajar cuando parametrizada por T y f.Hay otros idiomáticas repetitivo de soluciones libres?

Gracias!

¿Fue útil?

Solución

El problema con su makeLens es que queremos por ejemplo makeLens[Content]('foo) error en tiempo de compilación, y que no es posible con una ordinaria Symbol argumento.Necesita argumentos implícitos para seguir el singleton tipo para el nombre y para proporcionar evidencia de que es el nombre de un miembro de el caso de la clase:

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]

Y luego:

scala> case class Content(field: Int)
defined class Content

scala> makeLens[Content]('field)
res0: shapeless.Lens[Content,Int] = shapeless.Lens$$anon$6@7d7ec2b0

Pero makeLens[Content]('foo) no compile (que es lo que queremos).

Usted necesita el mismo tipo de seguimiento para su nestedMapLens:

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

Tenga en cuenta que estoy asumiendo un build.sbt como este:

scalaVersion := "2.11.2"

libraryDependencies ++= Seq(
  "com.chuusai" %% "shapeless" % "2.0.0",
  "org.typelevel" %% "shapeless-scalaz" % "0.3"
)

Ahora vamos a definir un ejemplo de mapa y algunos lentes:

val myMap = Map("foo" -> Map(1 -> Content(13)))

val myFoo1Lens = LensesFor[Content].nestedMapLens("foo", 1, 'field)
val myBar2Lens = LensesFor[Content].nestedMapLens("bar", 2, 'field)

Y luego:

scala> myFoo1Lens.get(myMap)
res4: Option[Int] = Some(13)

scala> myBar2Lens.get(myMap)
res5: Option[Int] = None

Esto es acerca de como "repetitivo" libre de como vas a conseguir.El desordenado argumento implícito de las listas son intimidante al principio, pero te acostumbras a ellos con bastante rapidez, y su papel en la conjunción de los diferentes bits de la evidencia acerca de los tipos que estás trabajando hace bastante intuitivo después de un poco de práctica.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top