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