Question

Basé sur:

import shapeless._

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

Je suis en train de faire un objectif-méthode de création, quelque chose de long:

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

Mais il semble que la non-évidence.Est-il possible de le faire?

Si pas, le résultat final, je suis en train de réaliser est une méthode générique pour la mise à jour de imbriquées, des Cartes avec des cas-contenu de classe, par exemple:

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)

Je ne peux pas le faire fonctionner quand paramétrée par T et f.Existe-il d'autres idiomatiques réutilisable sans solutions?

Merci!

Était-ce utile?

La solution

Le problème avec votre makeLens c'est que nous voulons par exemple makeLens[Content]('foo) l'échec au moment de la compilation, et ce n'est pas possible avec un simple Symbol argument.Vous avez besoin d'un peu plus implicite arguments pour suivre le singleton de type pour le nom donné et de fournir la preuve que c'est le nom d'un membre de la classe de cas:

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]

Et puis:

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

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

Mais makeLens[Content]('foo) ne compile pas (ce qui est ce que nous voulons).

Vous avez besoin du même type de suivi pour votre 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)
    )
}

Notez que je suis en supposant une build.sbt comme ceci:

scalaVersion := "2.11.2"

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

Maintenant, nous allons définir un exemple de carte et de certains objectifs:

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

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

Et puis:

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

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

C'est à peu près aussi "passe-partout" sans que vous allez obtenir.Le désordre implicite des listes d'arguments sont intimidant au début, mais on s'habitue assez rapidement, et leur rôle dans la de rassembler les différents bits de données sur les types avec qui vous travaillez devient assez intuitif après un peu de pratique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top