Knows Not Much
Knows Not Much

Reputation: 31546

Clean way of doing Pattern matching on shapeless Coproduct

I found out two ways which I can do pattern matching on a shapeless coproduct. I also googled this subject and found this

import shapeless._

object ShapelessEx3 extends App {
   case class Red()
   case class Green()
   case class Blue()
   type Colors = Red :+: Green :+: Blue :+: CNil
   val blue = Coproduct[Colors](Blue())
   val green = Coproduct[Colors](Green())
   printColor1(blue)
   printColor2(green)

   def printColor1(c: Colors) : Unit = {
      (c.select[Red], c.select[Green], c.select[Blue]) match {
         case (Some(_), None, None) => println("Color is red")
         case (None, Some(_), None) => println("Color is green")
         case (None, None, Some(_)) => println("Color is blue")
         case _ => println("unknown color")
      }
   }
   def printColor2(c: Colors) : Unit = {
      c match {
         case Inl(Red()) => println("color is red")
         case Inr(Inl(Green())) => println("color is green")
         case Inr(Inr(Inl(Blue()))) => println("color is blue")
         case _ => println("unknown color")
      }
   }
}

But both the functions are very noisy like case (None, Some(_), None) or Inr(Inr(Inl(Blue()))). How can I so a simple pattern matching like

c match {
  case Red() =>
  case Green() => 
  case Blue() => 
}

Upvotes: 1

Views: 1081

Answers (2)

Brendan Maguire
Brendan Maguire

Reputation: 4541

Just extending on the earlier answer. The Coproduct#fold method is a better equivalent to match case functionality.

import shapeless._
case class Red()
case class Green()
case class Blue()
type Colors = Red :+: Green :+: Blue :+: CNil

val blue = Coproduct[Colors](Blue())

object printColor extends Poly1 {
  implicit def caseRed   = at[Red](red => println("red"))
  implicit def caseBlue  = at[Blue](blue => println("blue"))
  implicit def caseGreen = at[Green](green => println("green"))
}

// This is equivalent to a match - case block
val printBlueResult: Unit = blue.fold(printColor)

object mapColor extends Poly1 {
  implicit def caseRed   = at[Red](red => 1)
  implicit def caseBlue  = at[Blue](blue => "a")
  implicit def caseGreen = at[Green](green => true)
}

// This maps the Coproduct to a new Coproduct
val mapBlueResult: Int :+: Boolean :+: String :+: CNil = blue.map(mapColor)

Upvotes: 0

Arnon Rotem-Gal-Oz
Arnon Rotem-Gal-Oz

Reputation: 25909

you can use Poly1 e.g.

import shapeless._
case class Red()
case class Green()
case class Blue()
type Colors = Red :+: Green :+: Blue :+: CNil
val blue = Coproduct[Colors](Blue())
val green = Coproduct[Colors](Green())

object printColor extends Poly1 {
  implicit def caseRed = at[Red] {r=> println("red") ;r    }
  implicit def caseBlue = at[Blue]{b=> println("blue");b  }
  implicit def caseGreen= at[Green]{g =>println("green");g }
}                                                             
green map printColor
blue map printColor

Upvotes: 8

Related Questions