Scala:как понять метод flatMap Try?

метод flatMap успеха реализуется следующим образом:

  def flatMap[U](f: T => Try[U]): Try[U] =
    try f(value)
    catch {
      case NonFatal(e) => Failure(e)
    }

Я вроде понимаю, что делает этот метод, это помогает нам избежать написания много кода ловли.

но в каком смысле он похож на обычную плоскую карту?

обычная плоская карта принимает последовательность последовательностей и помещает все элементы в одну большую "плоскую" последовательность.

но метод flatMap Try на самом деле ничего не выравнивает.

Так, как понять метод flatMap Try?

6 ответов


не входя в монады, вместо того, чтобы думать об этом с точки зрения коллекций, Вы могли бы думать об этом с точки зрения структур (где коллекция становится структурой со многими записями).

теперь взгляните на подпись Try.flatmap (из вашего поста):

def flatMap[U](f: T => Try[U]): Try[U] функции f преобразует T в Try[U] в контексте Try[T].

напротив, представьте, что операция была "карта", результат будет быть:

def badMap[U](f: T => Try[U]): Try[Try[U]]

как вы можете видеть, flatmap "сплющивает" результат в контексте Try[T] и производит Try[U] вместо вложенных Try[Try[U]].

вы можете применить ту же концепцию "сплющивания вложенной структуры" к коллекциям, о которой Вы упомянули.


вы можете рассматривать Try[T] как подобную коллекции только одного элемента (например, Option[T]).

когда "последовательность последовательностей" - "только одна последовательность", map и flatmap почти похожи. Единственное отличие-это сигнатура функции.

в этом случае выравнивание не требуется.


Я нашел Дэна Спивака "Монады-Это Не Метафоры " очень полезно, чтобы получить мою голову вокруг монад. Для людей, начинающих со Scala (как я), это намного легче понять, чем все, что я нашел, включая сочинения Одерского. Читая его, обратите внимание, что 'привязать'=='помощью flatMap'.


Как вы можете прочитать в экскурсия по Scala: последовательность постижений: "В scala каждый тип данных, который поддерживает операции filter, map и flatMap (с соответствующими типами), может использоваться в последовательном понимании.- На самом деле это означает, что ты можешь угрожать ему, как монада.
И flatMap для монады имеют такую подпись:

def flatMap(f: A => M[B]): M[B]

все коллекции в scala имеют монадические интерфейсы, поэтому вы можете рассматривать монадические операции в этой узкой области как операции на последовательности. Но это еще не все. В случае некоторых монад, смотрящих на них, как на коллекции, более запутанно, чем полезно. Обычно flatMap применяет преобразование "содержимого" монады, составляя эту монаду с операцией, приводящей к другому экземпляру монады того же типа. Таким образом, вы можете смотреть на монады, по крайней мере, двумя способами:

  • монада - это какая-то коллекция (или коробка, содержащая что-то), а элементы этой коллекции - "контент".
  • монады является ли какой-то контекст и элементы монады-это просто некоторые вычисления, сделанные в этом контексте.

иногда легче думать о монаде как о коллекции, иногда легче думать о ней как о контексте. По крайней мере для меня. Фактически оба подхода взаимозаменяемы, т. е. вы можете рассматривать списки (коллекции) как недетерминированные вычисления, которые могут возвращать произвольное количество результатов.

поэтому в случае попытки было бы проще думать об этом как контекст выполнения с двумя состояниями: успех и неудача. Если вы хотите составить несколько попыток, и одна из них находится в состоянии сбоя, тогда весь контекст становится сбоем (цепь нарушена). В противном случае вы можете выполнить некоторые операции над "содержимым" этой попытки, и контекст будет успешным.


обычная плоская карта принимает последовательность последовательностей и помещает все элементы в одну большую "плоскую" последовательность.

небольшая коррекция:

обычный flatMap принимает последовательность (в более общем случае монаду) , имеет аргумент, который является функцией, преобразующей элемент в последовательность (монаду), и возвращает "плоскую" последовательность (монаду).

для целей сравнения, кровавые подцепы, упомянутые здесь:). The flatmap метод перебирает вызов последовательности ввода f(element), но создает особую новой последовательности. "Сплющенная" часть применяется после каждого применения аргумента функции,f(element) - он выполняет вложенную итерацию над результирующей подпоследовательностью, получая каждую запись в сингулярной последовательности результатов.

в эквиваленте Success С value внутри (в более общем плане монаду):

  • flatmap есть аргумент, который является функцией преобразования Success на Try = Success(value) или Failure(exception). После f(value) применяется, результат уже является Try. "Сплющенная" часть является тривиальной / нулевой операцией: итерация по этому результату функции даст только одну запись, следовательно Try/Success/Failure даже не нужно реализовывать Iterable). Не обертывает дополнительные слои Success/Failure, и поэтому возвращает "плоский"Try.

    т. е. "Плоская" часть означает, что она не каскадирует Success/Failure обертки, так же, как последовательность flatmap не каскадные последовательности в иерархии (дерево значений).

  • это разные map, чей аргумент является функцией преобразования Success в произвольный тип U, после f(value) применяется, карта должна добавить дополнительный слой нового Success/Failure обтекание value/exception.


обычная плоская карта принимает последовательность последовательностей и помещает все элементы в одну большую "плоскую" последовательность

было бы справедливо заменить последовательность слов на монаду здесь, потому что эта операция не относится только к коллекции, на самом деле коллекции также являются монадами. Подумайте о Try как коллекция, которая может содержать либо Success стоимостью Failure