Scala: как понять метод FlatMap Try?
Метод FlatMap Успеха выполняется следующим образом:
def flatMap[U](f: T => Try[U]): Try[U] =
try f(value)
catch {
case NonFatal(e) => Failure(e)
}
Я понимаю, что делает этот метод, это помогает нам избежать написания большого количества ловушек.
Но в каком смысле он похож на обычную flatMap?
Регулярная flatMap берет последовательность последовательностей и помещает все элементы в одну большую "плоскую" последовательность.
Но метод FlatMap Try не совсем сглаживает что-либо.
Итак, как понять метод FlatMap Try?
Ответы
Ответ 1
Не вступая в монады, вместо того, чтобы думать об этом с точки зрения коллекций, вы можете думать об этом в терминах структур (где коллекция становится структурой со многими записями).
Теперь взглянем на подпись Try.flatmap
(из вашего сообщения):
def flatMap[U](f: T => Try[U]): Try[U]
функция f
преобразует T в Try [U] в контексте Try [T].
В противоположность этому, представьте, что операция была "map", результатом будет:
def badMap[U](f: T => Try[U]): Try[Try[U]]
Как вы можете видеть, flatmap "сглаживает" результат в контексте Try [T] и создает Try[U]
вместо вложенного Try[Try[U]]
.
Вы можете применить ту же концепцию "сглаживания вложенной структуры" к коллекциям, как вы упоминаете.
Ответ 2
Вы можете считать Try [T] похожим на коллекцию только одного элемента (например, Option [T]).
Когда "последовательность последовательностей" является "только одной последовательностью", карта и плоская карта почти одинаковы.
Единственная разница - это подпись функции.
В этом случае не требуется сплющивание.
Ответ 3
Я нашел Дэна Спивака " Монады не метафоры" очень полезно в моей голове вокруг монадов. Для людей, начинающих с Scala (как и я), это намного легче понять, чем что-либо еще, что я нашел - в том числе Odersky. Прочитав это, обратите внимание, что 'bind' == 'flatMap'.
Ответ 4
Как вы можете прочитать в Прогулка по Scala: Понятия последовательности:
"В scala каждый тип данных, который поддерживает фильтр операций, map и flatMap (с соответствующими типами), может использоваться при последовательных вычислениях". На самом деле это означает, что вы можете угрожать ему, как монаде.
И flatMap для монады имеют такую подпись:
def flatMap(f: A => M[B]): M[B]
Все коллекции в scala имеют монадические интерфейсы, поэтому вы можете смотреть на монадические операции в этой узкой области действия как операции над последовательностями. Но это еще не все. В случае, когда некоторые монады, глядя на них, как на коллекции, более запутанны, чем полезны. Как правило, flatMap применяет преобразование "содержания" монады, составляя эту монаду с помощью операции, приводящей к другому экземпляру монады того же типа.
Таким образом, вы можете смотреть на монады по крайней мере двумя способами:
- Монада - это своего рода коллекция (или поле, где-то что-то), а элементы этой коллекции - "контент".
- Монада - это какой-то контекст, а элементы монады - это просто некоторые вычисления, сделанные в этом контексте.
Иногда легче думать о монаде как коллекции, иногда легче думать об этом как о контексте. По крайней мере для меня. На самом деле оба подхода взаимозаменяемы, т.е. Вы можете просматривать списки (коллекции) как недетерминированные вычисления, которые могут возвращать произвольное количество результатов.
Итак, в случае Try это может быть проще думать об этом как контексте исполнения, с двумя состояниями: Успех и Неудача. Если вы хотите составить несколько Tries, а затем один из них находится в состоянии Failure, тогда весь контекст станет Failure (цепочка сломана). В противном случае вы можете выполнять некоторые операции над "контентом" этого Tries, а контекст - "Успех".
Ответ 5
Регулярная flatMap берет последовательность последовательностей и помещает все элементы в одну большую "плоскую" последовательность.
Небольшая коррекция:
Регулярный flatMap
принимает последовательность (в общем случае монаду), имеет аргумент, который является функцией, преобразующей элемент в последовательность (monad), и возвращает "плоскую" последовательность (monad).
В целях сравнения упомянутые здесь подстановки уровня gory:). Метод flatMap
выполняет итерацию по входной последовательности, вызывающей f(element)
, но создает единственную новую последовательность результатов. Часть "сплющивания" применяется после каждого приложения аргументов функции, f(element)
- она выполняет вложенную итерацию по полученной подпоследовательности, давая каждую запись в единственной последовательности результатов.
Эквивалент для Success
, с value
внутри (чаще всего монада):
-
flatMap
имеет аргумент, который является функцией преобразования Success
в Try
= Success(value)
OR Failure(exception)
. После применения f(value)
результат уже равен Try
. "Сплющенная" часть является тривиальной/нулевой операцией: итерация по этому результату функции даст только одну запись, поэтому Try
/Success
/Failure
даже не нужно реализовывать Iterable
). Не обертывает дополнительные слои Success
/Failure
, и поэтому возвращает "плоский" Try
.
т.е. "Плоская" часть означает, что она не каскадирует обертки Success
/Failure
, так как последовательность flatMap
не выполняет каскадные последовательности в иерархии (дерева значений).
-
это отличается от map
, аргументом которого является функция, преобразующая Success
в произвольный тип U
; после применения f(value)
карта должна добавить дополнительный слой новой Success
/Failure
, обертывающей вокруг value
/exception
.
Ответ 6
Регулярная flatMap принимает последовательность последовательностей и помещает все элементы в одну большую "плоскую" последовательность
Было бы справедливо заменить последовательность слов на монаду здесь, потому что эта операция не относится только к коллекции, на самом деле коллекции также являются монадами. Подумайте о Try
как коллекции, которая может содержать значение Success
Failure