문제

기준:

import shapeless._

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

나는 다음과 같은 렌즈 생성 방법을 만들려고 노력하고 있습니다.

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

그러나 그것은 분명하지 않은 것 같습니다.할 수 있습니까?

그렇지 않은 경우, 내가 달성하려는 최종 결과는 케이스 클래스 콘텐츠로 중첩된 지도를 업데이트하는 일반적인 방법입니다. 예:

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)

T와 f로 매개변수화하면 작동하게 할 수 없습니다.상용구가 없는 다른 관용적 솔루션이 있나요?

감사해요!

도움이 되었습니까?

해결책

당신의 문제 makeLens 예를 들어 우리가 원하는 것입니다. makeLens[Content]('foo) 컴파일 타임에 실패하는 것은 일반적인 경우에는 불가능합니다. Symbol 논쟁.주어진 이름에 대한 싱글톤 유형을 추적하고 그것이 케이스 클래스 멤버의 이름이라는 증거를 제공하려면 몇 가지 추가 암시적 인수가 필요합니다.

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]

그런 다음:

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

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

하지만 makeLens[Content]('foo) 컴파일되지 않습니다(우리가 원하는 것입니다).

귀하에게도 동일한 종류의 추적이 필요합니다. 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)
    )
}

내가 가정하고 있다는 점에 유의하세요. build.sbt 이와 같이:

scalaVersion := "2.11.2"

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

이제 예제 맵과 일부 렌즈를 정의해 보겠습니다.

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

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

그런 다음:

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

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

이것은 당신이 얻게 될 "상용구가 없는" 정도입니다.지저분한 암시적 인수 목록은 처음에는 겁이 나지만 꽤 빨리 익숙해지고 작업 중인 유형에 대한 다양한 증거를 모으는 역할은 약간의 연습 후에 상당히 직관적이 됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top