DANG Fan
DANG Fan

Reputation: 864

Shapeless: map a tuple with some options to options

Having

(Some(1), 2, Some(3))

I expect to get

(Some(1), Some(2), Some(3))

With shapeless is it possible to do so?

Upvotes: 6

Views: 751

Answers (2)

Miles Sabin
Miles Sabin

Reputation: 23056

Yes it is,

scala> import shapeless._, syntax.std.tuple._
import shapeless._
import syntax.std.tuple._

scala> :paste
// Entering paste mode (ctrl-D to finish)

object opt extends opt0 {
  implicit def optId[T <: Option[_]] = at[T](identity)
}
trait opt0 extends Poly1 {
  implicit def default[T] = at[T](Option(_))
}

// Exiting paste mode, now interpreting.

defined object opt
defined trait opt0

scala> (Some(1), 2, Some(3)) map opt
res0: (Some[Int], Option[Int], Some[Int]) = (Some(1),Some(2),Some(3))

You'll notice that the Some[Int]'s at the first and last position have been preserved whereas the lifted middle element is typed as Option[Int]. I've worked on the assumption that what you actually intended was something like this,

scala> (Option(1), 2, Option(3)) map opt
res1: (Option[Int], Option[Int], Option[Int]) = (Some(1),Some(2),Some(3))

Upvotes: 7

Mateusz Dymczyk
Mateusz Dymczyk

Reputation: 15141

Yes shapeless can do a lot!

  import shapeless._
  import syntax.std.tuple._

  trait basicOption extends Poly1 {
    implicit def default[T] = at[T](t => Some(t))
  }

  object fullOption extends basicOption {
    implicit def caseSome[T] = at[Some[T]](s => s)
    implicit def caseNone = at[None.type](s => s)
  }

  println((Some(1),2,Some(3)).map(fullOption)) // (Some(1),Some(2),Some(3))
  println((Some(1),2,None).map(fullOption)) // (Some(1), Some(2), None)

For more examples you can check their github repo

This is for Shapeless 2.0 and up, if you are using something older you can still do it but instead of calling map on the tuple directly you would have to go through a HList.

Upvotes: 6

Related Questions