Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't scala.util.Try implement GenTraversableOnce?

Thanks to the latest offering from Martin Odersky on Coursera, I have begun playing with scala.util.Try. However, I was surprised to find that it doesn't necessarily play well with the collection monads because it doesn't implement scala.collection.GetTraversableOnce.

This could come in handy. For instance, you could convert a list of strings to integers while throwing out the bad ones like this:

def ints(strs:List[String]):List[Int] = strs.flatMap(s => Try(s.toInt))

The workaround is simple. Just convert the Try to an Option and let its implicit conversion work for us:

def ints(strs:List[String]):List[Int] = strs.flatMap(s => Try(s.toInt).toOption)

Seems to me that Try would either implement GenTraversableOnce or have its own implicit conversion. Can anyone explain why it doesn't? Is it simply the fact Try isn't actually a monad?

like image 367
joescii Avatar asked Nov 09 '13 12:11

joescii


1 Answers

It's a Monad, but in my opinion, it's really not a collection in the way you're trying to use it. FlatMap is not for translating between different monads (M[A]=>M[B], yes, but not M[A]=>N[B] or even M[A]=>N[A]). It feels more like you want something like:

import scala.util.{Try, Success}

def ints2(strs: List[String]): List[Int] =
  strs.map { s => Try(s.toInt) }.collect { case Success(n) => n }

or

import scala.util.{Try, Success, Failure}

def ints3(strs: List[String]): List[Int] = strs.flatMap { s =>
    Try(s.toInt) match {
        case Success(n) => List(n)
        case Failure(ex) => List.empty
    }
}

=>

scala> ints2(List("1","2","a","3"))
res8: List[Int] = List(1, 2, 3)
like image 181
Rob Starling Avatar answered Nov 15 '22 21:11

Rob Starling