Use functional combinators on Scala Tuples? - scala

'map' preserves the number of elements, so using it on a Tuple seems sensible.
My attempts so far:
scala> (3,4).map(_*2)
error: value map is not a member of (Int, Int)
(3,4).map(_*2)
^
scala> (3,4).productIterator.map(_*2)
error: value * is not a member of Any
(3,4).productIterator.map(_*2)
^
scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2)
res4: Iterator[Int] = non-empty iterator
scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2).toList
res5: List[Int] = List(6, 8)
It looks quite painful... And I haven't even begun to try to convert it back to a tuple.
Am I doing it wrong? Could the library be improved?

In general, the element types of a tuple aren't the same, so map doesn't make sense. You can define a function to handle the special case, though:
scala> def map[A, B](as: (A, A))(f: A => B) =
as match { case (a1, a2) => (f(a1), f(a2)) }
map: [A,B](as: (A, A))(f: (A) => B)(B, B)
scala> val p = (1, 2)
p: (Int, Int) = (1,2)
scala> map(p){ _ * 2 }
res1: (Int, Int) = (2,4)
You could use the Pimp My Library pattern to call this as p.map(_ * 2).
UPDATE
Even when the types of the elements are not the same, Tuple2[A, B] is a Bifunctor, which can be mapped with the bimap operation.
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> val f = (_: Int) * 2
f: (Int) => Int = <function1>
scala> val g = (_: String) * 2
g: (String) => String = <function1>
scala> f <-: (1, "1") :-> g
res12: (Int, String) = (2,11)
UPDATE 2
http://gist.github.com/454818

shapeless Supports mapping and folding over tuples via an intermediary HList representation,
Sample REPL session,
scala> import shapeless._ ; import Tuples._
import shapeless._
import Tuples._
scala> object double extends (Int -> Int) (_*2)
defined module double
scala> (3, 4).hlisted.map(double).tupled
res0: (Int, Int) = (6,8)
Where the elements of the tuple are of different types you can map with a polymorphic function with type-specific cases,
scala> object frob extends Poly1 {
| implicit def caseInt = at[Int](_*2)
| implicit def caseString = at[String]("!"+_+"!")
| implicit def caseBoolean = at[Boolean](!_)
| }
defined module frob
scala> (23, "foo", false, "bar", 13).hlisted.map(frob).tupled
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26)
Update
As of shapeless 2.0.0-M1 mapping over tuples is supported directly. The above examples now look like this,
scala> import shapeless._, poly._, syntax.std.tuple._
import shapeless._
import poly._
import syntax.std.tuple._
scala> object double extends (Int -> Int) (_*2)
defined module double
scala> (3, 4) map double
res0: (Int, Int) = (6,8)
scala> object frob extends Poly1 {
| implicit def caseInt = at[Int](_*2)
| implicit def caseString = at[String]("!"+_+"!")
| implicit def caseBoolean = at[Boolean](!_)
| }
defined module frob
scala> (23, "foo", false, "bar", 13) map frob
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26)

map function gets an A => B and returns F[B].
def map[A, B](f: A => B) : F[B]
As retronym wrote Tuple2[A, B] is a Bifunctor, so you can look for the bimap function in scalaz or cats.
bimap is a function that maps both sides of the tuple:
def bimap[A, B, C, D](fa: A => C, fb: B => D): Tuple2[C, D]
Because Tuple[A, B] holds 2 values and only one value can be mapped (by convention the right value), you can just return the same value for the left side and use the right
function to map over the right value of the tuple.
(3, 4).bimap(identity, _ * 2)

Related

Scala Match Error On Tuple With Parameterized Type

I'm trying to write some generic testing software for various types using a parameterized base class. I get match errors though on code which I don't believe should be possible.
abstract class AbstractTypeTest[TestType: ClassTag, DriverType <: AnyRef : ClassTag](
def checkNormalRowConsistency(
expectedKeys: Seq[TestType],
results: Seq[(TestType, TestType, TestType)]) {
val foundKeys = results.filter {
case (pkey: TestType, ckey: TestType, data: TestType) => expectedKeys.contains(pkey)
case x => throw new RuntimeException(s"${x.getClass}")
}
foundKeys should contain theSameElementsAs expectedKeys.map(x => (x, x, x))
}
}
An extending class specifies the parameter of TypeTest but this code block throws Runtime Exceptions (because we don't match what I believe should be the only allowed type here)
The output of the above code with some extended types works but with others it does not, in this case I'm extending this class with TestType --> Int
[info] java.lang.RuntimeException: class scala.Tuple3
I can remove the type on the filter and the ScalaTest check works perfectly but I'd like to understand why the MatchError occurs.
If you're on Scala 2.10, then
ClassTag based pattern matching fails for primitives
scala> import reflect._
import reflect._
scala> def f[A: ClassTag](as: Seq[(A,A,A)]) = as filter {
| case (x: A, y: A, z: A) => true ; case _ => false }
f: [A](as: Seq[(A, A, A)])(implicit evidence$1: scala.reflect.ClassTag[A])Seq[(A, A, A)]
scala> val vs = List((1,2,3),(4,5,6))
vs: List[(Int, Int, Int)] = List((1,2,3), (4,5,6))
scala> f(vs)
res0: Seq[(Int, Int, Int)] = List()
versus 2.11
scala> f[Int](vs)
res4: Seq[(Int, Int, Int)] = List((1,2,3), (4,5,6))

Diverging implicit expansion for type shapeless.Typeable[...]

I have a value of type Any. If its class is Map[String, Any] I must be able to cast it to a case class and for this purpose I'm using the solution proposed by Travis Brown here. The problem is that when I define a Typeable implementation as the following, in certain cases, I get the diverging implicit expansion error:
implicit def caseClassTypeable[T, R <: HList](implicit castT: Typeable[T],
gen: LabelledGeneric.Aux[T, R],
fromMap: FromMap[R]) =
new Typeable[T] {
override def cast(t: Any): Option[T] = t.cast[Map[String, Any]] flatMap (m => to[T].from(m))
override def describe: String = castT.describe
}
REPL session:
scala> import shapeless.syntax.typeable._
import shapeless.syntax.typeable._
scala> case class Simple(foo: String, bar: Int)
defined class Simple
scala> val m: Any = Map("foo" -> "a", "bar" -> 42)
m: Any = Map(foo -> a, bar -> 42)
scala> m.cast[Simple]
res7: Option[Simple] = Some(Simple(a,42))
scala> val l: Any = List(1, 2, 3)
l: Any = List(1, 2, 3)
scala> l.cast[List[Any]]
<console>:22: error: diverging implicit expansion for type shapeless.Typeable[List[Any]]
starting with method inrTypeable in object Typeable
l.cast[List[Any]]
^
However this one works:
scala> l.cast[List[Int]]
res9: Option[List[Int]] = Some(List(1, 2, 3))
Any idea?

How to flatten a nested tuple?

I have a nested tuple structure like (String,(String,Double)) and I want to transform it to (String,String,Double). I have various kinds of nested tuple, and I don't want to transform each manually. Is there any convenient way to do that?
If you use shapeless, this is exactly what you need, I think.
There is no flatten on a Tupple. But if you know the structure, you can do something like this:
implicit def flatten1[A, B, C](t: ((A, B), C)): (A, B, C) = (t._1._1, t._1._2, t._2)
implicit def flatten2[A, B, C](t: (A, (B, C))): (A, B, C) = (t._1, t._2._1, t._2._2)
This will flatten Tupple with any types. You can also add the implicit keyword to the definition. This works only for three elements. You can flatten Tupple like:
(1, ("hello", 42.0)) => (1, "hello", 42.0)
(("test", 3.7f), "hi") => ("test", 3.7f, "hi")
Multiple nested Tupple cannot be flatten to the ground, because there are only three elements in the return type:
((1, (2, 3)),4) => (1, (2, 3), 4)
Not sure about the effiency of this, but you can convert Tuple to List with tuple.productIterator.toList, then flatten the nested lists:
scala> val tuple = ("top", ("nested", 42.0))
tuple: (String, (String, Double)) = (top,(nested,42.0))
scala> tuple.productIterator.map({
| case (item: Product) => item.productIterator.toList
| case (item: Any) => List(item)
| }).toList.flatten
res0: List[Any] = List(top, nested, 42.0)
Complement of answer above
Paste this utility code:
import shapeless._
import ops.tuple.FlatMapper
import syntax.std.tuple._
trait LowPriorityFlatten extends Poly1 {
implicit def default[T] = at[T](Tuple1(_))
}
object flatten extends LowPriorityFlatten {
implicit def caseTuple[P <: Product](implicit lfm: Lazy[FlatMapper[P, flatten.type]]) =
at[P](lfm.value(_))
}
then you are able to flatten any nested tuple:
scala> val a = flatten(((1,2),((3,4),(5,(6,(7,8))))))
a: (Int, Int, Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6,7,8)
Note that this solution does not work for self-defined case class type, which would be converted to String in the output.
scala> val b = flatten(((Cat("c"), Dog("d")), Cat("c")))
b: (String, String, String) = (c,d,c)
In my opinion simple pattern matching would work
scala> val motto = (("dog", "food"), "tastes good")
val motto: ((String, String), String) = ((dog,food),tastes good)
scala> motto match {
| case ((it, really), does) => (it, really, does)
| }
val res0: (String, String, String) = (dog,food,tastes good)
Or if you have a collection of such tuples:
scala> val motto = List(
| (("dog", "food"), "tastes good")) :+ (("cat", "food"), "tastes bad")
val motto: List[((String, String), String)] = List(((dog,food),tastes good), ((cat,food),tastes bad))
scala> motto.map {
| case ((one, two), three) => (one, two, three)
| }
val res2: List[(String, String, String)] = List((dog,food,tastes good), (cat,food,tastes bad))
I think it would be convenient even if you have several cases.

Structural subtyping reflection

Can we get the type of val s: String using reflection from the outside of the function f?
val f = (r: {val s: String}) => {
}
scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> def typeOf[T: ru.TypeTag](x: T) = ru.typeOf[T] // capture compile-time type info
typeOf: [T](x: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type
scala> val f = (r: {val s: String}) => {}
f: AnyRef{val s: String} => Unit = <function1>
scala> val tpe = typeOf(f)
tpe: reflect.runtime.universe.Type = scala.AnyRef{val s: String} => Unit
scala> ru.showRaw(tpe)
res0: String = TypeRef(ThisType(scala), scala.Function1, List(RefinedType(List(TypeRef(ThisType(scala), newTypeName("AnyRef"), List())), Scope(newTermName("s"))), TypeRef(ThisType(scala), scala.Unit, List())))
scala> val ru.TypeRef(_, _, refinement :: _) = tpe
refinement: reflect.runtime.universe.Type = scala.AnyRef{val s: String}
With Scala reflection one can also generate mocks for structural types as follows: https://gist.github.com/4008389. The linked gist does this using toolboxes and runtime reflection, but this scenario looks implementable with macros as well.

Can I use monad transformers to simplify this composition?

suppose I have
type VS[A] = Validation[String, A]
val v: VS[Option[A]]
val f: A => VS[B]
I want to get a result of type VS[Option[B]] but if v is a Success(None), the result should also be a Success(None). Here's an example:
scala> val v: VS[Option[String]] = some("4.5").success
v: VS[Option[String]] = Success(Some(4.5))
scala> val f = (s : String) => (try { s.toInt.success } catch { case x => x.getMessage.fail }): VS[Int]
f: String => VS[Int] = <function1>
Then:
scala> import Validation.Monad._
import Validation.Monad._
scala> (v map2 f map (_.sequence)).join
res4: scalaz.Validation[String,Option[Int]] = Failure(For input string: "4.5")
The success case is:
scala> val v: VS[Option[String]]= some("5").success
v: VS[Option[String]] = Success(Some(5))
scala> (v map2 f map (_.sequence)).join //UGLY composition
res7: scalaz.Validation[String,Option[Int]] = Success(Some(5))
And the empty case is:
scala> val v: VS[Option[String]]= none[String].success
v: VS[Option[String]] = Success(None)
scala> (v map2 f map (_.sequence)).join
res6: scalaz.Validation[String,Option[Int]] = Success(None)
Is there a "nicer" way of doing this (possibly involving kleisli composition or monad transformers)?
The monad transformer OptionT does exactly what you want here, and its flatMapF method makes usage a clean one-liner.
I'm going to use Scalaz 7's disjunction type (\/) instead of Validation in this example, since the latter isn't a monad in Scalaz 7, but the principle is the same.
import scalaz._, std.option._, syntax.id._, syntax.monad._
type DS[+A] = String \/ A
type ODS[A] = OptionT[DS, A]
def f(s: String) = try s.toInt.right catch { case e => e.getMessage.left }
Now we can write the following:
scala> val v = OptionT(some("4.5").point[DS])
v: scalaz.OptionT[DS,java.lang.String] = OptionT(\/-(Some(4.5)))
scala> (v flatMapF f).run
res0: DS[Option[Int]] = -\/(For input string: "4.5")
Or equivalently:
scala> ("4.5".point[ODS] flatMapF f).run
res1: DS[Option[Int]] = -\/(For input string: "4.5")
Or the success case:
scala> ("4".point[ODS] flatMapF f).run
res2: DS[Option[Int]] = \/-(Some(4))
Or the empty case:
scala> (OptionT(none.point[DS]) flatMapF f).run
res3: DS[Option[Int]] = \/-(None)
As desired.