[SCALA] 스칼라 케이스 클래스에 업데이트 작업
SCALA스칼라 케이스 클래스에 업데이트 작업
나는 같은 유형의 두 인스턴스화 된 경우 클래스가 있습니다.
case class Foo(x : Option[String], y : Option[String], z : Option[String])
인스턴스화 된 클래스 A와 B를 호출하자
val a = Foo(x=Some("foo"), y=Some("bar"), z=Some("baz"))
val b = Foo(x=None, y=Some("etch"), z=None)
나는 일반적인 방법으로 한 번의 작업으로 B와 업데이트의 경우 클래스 A에 대한 경우의 수 궁금하네요.
val c = b *oper* a // produces Foo(x=Some("foo"), y=Some("etch"), z=Some("baz"))
없음 무시로 설정 매개 변수. 이 경우 클래스의 모든 유형에 역할을 할 수 있도록 이상적으로 작동 또한 일반적인해야한다.
아마도 ApplicativeBuilder를 사용하여 - 내가 처음 튜플 / 목록에 클래스를 변환 작업이 완료되면 클래스로 다시 변환하여 Scalaz이 작업을 수행 할 수있을 몇 가지 직관이? 나는 올바른 방법으로 이것에 대해 생각하고? 어떤 아이디어?
해결법
-
==============================
1.당신은 많은 세부 사항을 마무리하기 위해 반군 인스턴스를 사용할 수 있습니다 :
당신은 많은 세부 사항을 마무리하기 위해 반군 인스턴스를 사용할 수 있습니다 :
import scalaz._, Scalaz._ case class Foo(a: Option[String], b: Option[String], c: Option[String]) implicit object fooSemigroup extends Semigroup[Foo] { def fromFoo(f: Foo) = (f.a.fst, f.b.fst, f.c.fst) def toFoo(t: (FirstOption[String], FirstOption[String], FirstOption[String])) = Foo(t._1.value, t._2.value, t._3.value) def append(x: Foo, y: => Foo) = toFoo(fromFoo(x) |+| fromFoo(y)) }
어떤 우리를 제공합니다 :
scala> val a = Foo(Some("foo"), Some("bar"), Some("baz")) a: Foo = Foo(Some(foo),Some(bar),Some(baz)) scala> val b = Foo(None, Some("etch"), None) b: Foo = Foo(None,Some(etch),None) scala> b |+| a res11: Foo = Foo(Some(foo),Some(etch),Some(baz))
어느 나는 그것이 매우 일반적인하지 비록 당신이 원하는 것을 생각합니다.
당신이 (회원에 대한 적절한 타입의 클래스 인스턴스 주어진) 모든 경우 클래스 작동 뭔가를 원한다면, 당신은 볼품 및 Scalaz 다음과 같은 조합을 사용할 수 있습니다. 내가 missingfactor의 대답과 마일 사빈하여이 예에 그리기 야합니다. 우선 몇 가지 모노 이드 인스턴스 :
import scalaz._, Scalaz._ import shapeless._, HList._ implicit object hnilMonoid extends Monoid[HNil] { val zero = HNil def append(a: HNil, b: => HNil) = HNil } implicit def hlistMonoid[H, T <: HList]( implicit mh: Monoid[H], mt: Monoid[T] ): Monoid[H :: T] = new Monoid[H :: T] { val zero = mh.zero :: mt.zero def append(a: H :: T, b: => H :: T) = (a.head |+| b.head) :: (a.tail |+| b.tail) } implicit def caseClassMonoid[C, L <: HList]( implicit iso: Iso[C, L], ml: Monoid[L] ) = new Monoid[C] { val zero = iso.from(ml.zero) def append(a: C, b: => C) = iso.from(iso.to(a) |+| iso.to(b)) }
simplicitly 난 그냥 범위 옵션에 대해 "첫 번째"모노 이드 인스턴스를 넣어가는 대신에 내가 위에서 한 것처럼 FirstOption 래퍼를 사용하고의 이익을 위해 다음.
implicit def optionFirstMonoid[A] = new Monoid[Option[A]] { val zero = None def append(a: Option[A], b: => Option[A]) = a orElse b }
이제 우리의 경우 클래스 :
case class Foo(a: Option[String], b: Option[String], c: Option[String])
그리고 이소 인스턴스는 HList 다시로 변환합니다 :
implicit def fooIso = Iso.hlist(Foo.apply _, Foo.unapply _)
그리고 우리는 완료 :
scala> val a = Foo(Some("foo"), Some("bar"), Some("baz")) a: Foo = Foo(Some(foo),Some(bar),Some(baz)) scala> val b = Foo(None, Some("etch"), None) b: Foo = Foo(None,Some(etch),None) scala> b |+| a res0: Foo = Foo(Some(foo),Some(etch),Some(baz))
나는 떠날거야, 그래서 당신은 여기뿐만 아니라 monoids의 반군을 사용하고 몇 줄을 저장,하지만 훨씬 복사로 멀리 얻으려고 노력하고 가능한 한 볼품 / 예제 코드에서 붙여 넣기 한 수있는 운동으로.
여기 OrElse라는 (스칼라 2.9.2, IcedTea7 2.2.1)을 사용하여 표준 라이브러리 솔루션에 비해 후자의 솔루션을 완전히 비과학적인 벤치 마크 성능에 대한 의견을 해결하기 위해 :
def add(x: Foo, y: Foo) = Foo(x.a orElse y.a, x.b orElse y.b, x.c orElse y.c) def ros = if (util.Random.nextBoolean) Some(util.Random.nextString(util.Random.nextInt(10))) else None val foos = Seq.fill(500000)(Foo(ros, ros, ros)) def time(block: => Unit) = { val start = System.currentTimeMillis (block, System.currentTimeMillis - start) }
그리고 수십 배의 각각 커플을 실행 한 후 :
scala> Iterator.fill(10)(time(foos.reduce(add(_, _)))._2).sum / 10 res4: Long = 49 scala> Iterator.fill(10)(time(foos.reduce(_ |+| _))._2).sum / 10 res5: Long = 265
다소 놀랍게도, 볼품없는 Scalaz 솔루션은 조금 느립니다 :
scala> Iterator.fill(10)(time(foos.reduce(_.|+|(_)(fooSemigroup)))._2).sum / 10 res6: Long = 311
하지만 말했듯이,이 벤치마킹에 매우 즉석 접근 방식은, 당신은 (캘리퍼스이에 대한 좋은 라이브러리) 자신을 실행해야합니다.
어떤 경우에는, 그래, 당신은 추상화를 지불하고 있지만 그렇게 많이하지, 그것은 가치가에게 그것을로 종종 가능성이 높습니다.
-
==============================
2.이 스레드에서 설명하고있는 바와 같이, 이것은 당신이 완전히 형태 보증 된 방법으로, 볼품로 문제를 해결할 수있는 방법입니다.
이 스레드에서 설명하고있는 바와 같이, 이것은 당신이 완전히 형태 보증 된 방법으로, 볼품로 문제를 해결할 수있는 방법입니다.
scala> import shapeless._ import shapeless._ scala> import HList._ import HList._ scala> case class Foo(a: Option[Int], b: Option[Int]) defined class Foo scala> val a = Foo(Some(3), None) a: Foo = Foo(Some(3),None) scala> val b = Foo(Some(22), Some(1)) b: Foo = Foo(Some(22),Some(1)) scala> implicit val fooIso = HListIso(Foo.apply _, Foo.unapply _) fooIso: shapeless.HListIso[Foo,shapeless.::[Option[Int],shapeless.::[Option[Int],shapeless.HNil]]] = shapeless.HListIso@11c5b77 scala> type O2[+A] = (Option[A], Option[A]) defined type alias O2 scala> object mapper extends (O2 ~> Option) { | def apply[A](x: O2[A]): Option[A] = x._1.orElse(x._2) | } defined module mapper scala> fooIso.fromHList(fooIso.toHList(a).zip(fooIso.toHList(b)).map(mapper)) res13: Foo = Foo(Some(3),Some(1))
from https://stackoverflow.com/questions/11438277/update-operations-on-a-scala-case-class by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 표준 작업 이후에 자동으로 실행 사용자 지정 작업 / (0) | 2019.11.09 |
---|---|
[SCALA] 왜 하나는 해시 대신 점으로 스칼라 형 멤버를 선택 하는가? (0) | 2019.11.09 |
[SCALA] 두 목록의 직교 제품 (0) | 2019.11.09 |
[SCALA] 자바 8 스트림, 점점 머리와 꼬리 (0) | 2019.11.09 |
[SCALA] 자바 8 스트림 API와 정수의 목록을 셔플 (0) | 2019.11.09 |