0

I currently have something that looks like this:

data foreach {
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(a))))))))))))))))))) => /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Right(a)))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Right(a))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Right(a)))))) =>  /* Do something */
          case Left(Left(Left(Left(Right(a))))) =>  /* Do something */
          case Left(Left(Left(Right(a)))) =>  /* Do something */
          case Left(Left(Right(a))) =>  /* Do something */
          case Left(Right(a)) =>  /* Do something */
          case Right(a) =>  /* Do something */
        }

I was wondering if there is any way to implement some sort of recursive function to make my pattern matching cleaner. Something that would look more like this:

data foreach {
          case Foo(a, 3) =>  /* Do something */
          case Foo(a, 2) =>  /* Do something */
          case Foo(a, 1) =>  /* Do something */
          case Foo(a, 0) =>  /* Do something */
        }
Olshansky
  • 5,904
  • 8
  • 32
  • 47

1 Answers1

1

This is how I would do it.

object Test extends App {
  object Foo {
    def unapply[T: Manifest](e: Either[_, T]): Option[(T, Int)] = e match {
      case Right(rVal: T) => Some(Tuple2(rVal, 0))
      case Left(left: Either[_, T]) => left match {
        case Foo(rVal: T, d) => Some(Tuple2(rVal, d + 1))
        case _ => None
      }
      case _ => None
    }

    def apply[T, E <: Either[E, T]](t: T, d: Int): Either[E, T] = {
      Either.cond[E, T](d == 0, t, apply(t, d - 1).asInstanceOf[E])
    }
  }

  val data = List(
    Foo("a", 0),
    Foo("b", 2),
    Foo("c", 3),
    Foo("d", 10),
    Left(10)
  )

  data foreach println
  println()

  data collect {
    case Foo(a, 0) => println(s"$a at 0")
    case Foo(a, d) => println(s"Generic: $a at $d")
  }
}

This test app has this output:

// Right(a)
// Left(Left(Right(b)))
// Left(Left(Left(Right(c))))
// Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(d)))))))))))
// Left(10)
//
// a at 0
// Generic: b at 2
// Generic: c at 3
// Generic: d at 10
Nate
  • 2,205
  • 17
  • 21