복붙노트

[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. ==============================

    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. ==============================

    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))
    
  3. from https://stackoverflow.com/questions/11438277/update-operations-on-a-scala-case-class by cc-by-sa and MIT license