1

I want to map a pair of options of String like the following

val pair: (Option[String], Option[String]) = (Some("a"), None)

val mapped: (String, String) = pair map {case (a:Option[String],b:Option[String]) => (a.getOrElse(""),b.getOrElse(""))}

but the output signature is different from what I expected

(Option[String],(String,String))

It seems that I'm missing something here... maybe scalaz or shapeless allows for such functionality of mapping tuples?

stanislav.chetvertkov
  • 1,620
  • 3
  • 13
  • 24
  • I can not compile your code. – vvg Nov 09 '15 at 12:03
  • As it stands, this does not compile for me (and I would not expect it to - the type `Pair` / `Tuple2` doesn't have a `map` method). Is there a `List` or `Map` involved here that you have tried to take out to simplify the question? – Shadowlands Nov 09 '15 at 12:03
  • [Apparently shapeless does support `Tuple#map`](http://stackoverflow.com/a/10487475/2823715) – rahilb Nov 09 '15 at 12:07
  • @rahilb it was added at 2.0 version as mentioned in Miles's answer – Odomontois Nov 09 '15 at 15:15

2 Answers2

7

Simple change from map to match you'll get expected types.

scala>   val pair: (Option[String], Option[String]) = (Some("a"), None)
pair: (Option[String], Option[String]) = (Some(a),None)

scala>

scala>   val mapped: (String, String) = pair match {case (a:Option[String],b:Option[String]) => (a.getOrElse(""),b.getOrElse(""))}
mapped: (String, String) = (a,"")

scala>

scala>   mapped
res8: (String, String) = (a,"")
vvg
  • 6,325
  • 19
  • 36
  • it seems i got 'map' from scalaz imported, which is probably misled me) – stanislav.chetvertkov Nov 09 '15 at 12:08
  • @stanislav.chetvertkov `map` in scalaz treats `Tuple2` as monad. During `map` it will change only second part as defined [here](https://github.com/scalaz/scalaz/blob/c847654dcf75c748eacbaf246511bbd938b8631f/core/src/main/scala/scalaz/std/Tuple.scala#L941) – Odomontois Nov 09 '15 at 12:18
0

In case if you specifically want to do things like that with shapeless, you should make some preparations.

First tell your compiler what you want to use in case of None:

class Default[T](val value: T)

implicit object defaultString extends Default[String]("")

Now create your function to map:

import shapeless._

object extract extends Poly1 {
  implicit def withDefault[T](implicit default: Default[T]) =
    at[Option[T]](_ getOrElse default.value)
}

Now use shapeless extension for tuples:

import syntax.std.tuple._

pair.map(extract) // res0: (String, String) = (a,)
Odomontois
  • 15,918
  • 2
  • 36
  • 71