Почему не scala.util.Try реализовать GenTraversableOnce?

Благодаря последнему предложению Мартина Одерски на Coursera, я начал играть с scala.util.Try. Однако я с удивлением обнаружил, что он не обязательно хорошо сочетается с коллекционными монадами, потому что он не реализует scala.collection.GetTraversableOnce.

Это может пригодиться. Например, вы можете преобразовать список строк в целые числа, выбрасывая плохие, например:

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

Обходной путь прост. Просто преобразуйте Try в Option и пусть его неявное преобразование работает для нас:

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

Мне кажется, что Try будет либо реализовывать GenTraversableOnce, либо иметь собственное неявное преобразование. Может ли кто-нибудь объяснить, почему это не так? Это просто факт, что Try на самом деле не монада?

Ответ 1

Это Монада, но, на мой взгляд, это действительно не коллекция, в которой вы пытаетесь ее использовать. FlatMap не предназначен для перевода между разными монадами (M[A]=>M[B], да, но не M[A]=>N[B] или даже M[A]=>N[A]). Это похоже на то, что вы хотите что-то вроде:

import scala.util.{Try, Success}

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

или

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)