вроде scala-вских for-comprehensions?
Если да, то поголосуйте за тикет про это, пожалуйста.
(знаю, что в чатике есть мощные функциональщики, но сейчас интересует исключительно прагматическая сторона и применение в проде, без упоминая слова монады вообще c: )
Просто известно, что скалисты пользуются ими и в хвост, и гриву, в моем окружении тоже много кто хочет такое, но официально к тикету про это никакого интереса проявлено не было.
P.S. Для тех, кто не слышал про такое, супер-краткий обзор: функциональное программирование на котлине это круто, но часто оказывается, что читать вложенные преобразования данных функциями вида map и flatMap довольно тяжело, а ля callback hell.
Ну, совсем тупой пример еще даже на Java:
results.stream().flatMap(
res -> f(res).flatMap(
res1 -> res1.flatMap(
res2 -> res2.map( /* and so on */ ))));
И вот говоря очень кратко, for-comprehensions это простой синтаксический сахар для такого. Он применим для любых сущностей у которых есть методы вида map, flatMap и filter, например, Optional, List, Future, Flowable, Observable, Spring Stream's Flux и т.д, т.е. у дофигищи повседневных вещей.
И вот если в котлине будут for-comprehensions, то код вида
fun login(oldAuth: AuthToken): SomeContainer<UserModel>> {
credentialService.oauthLogin(oldAuth).flatMap { token ->
securityService.getRole(token).flatMap { role ->
credentialService.getUserDetails(token, role).map { userDetails ->
(token, role, userDetails)
}
}
}
.filter { (token, role, userDetails) -> areValidModelParams(token, role, userDetails) }
.flatMap { (token, role, userDetails) -> computeUserModel(token, role, userDetails) }
...
будет примерно выглядеть как
fun login(oldAuth: AuthToken): SomeContainer<UserModel> =
for {
token <- credentialService.oauthLogin(oldAuth)
role <- securityService.getRole(token)
userDetails <- credentialService.getUserDetails(token, role)
if areValidModelParams(token, role, userDetails)
userModel <- computeUserModel(token, role, userDetails)
}
yield userModel
По-моему это ужасно. Вообще не понятно, что оно делает. Не говоря о том, что пример плохой, если у вас там там что-то типа Optional, то в котлин оно вообще не нужно из-за нулябельности.
Ну для nullable типов, Result, а также Option, Either и Eval из Arrow есть собственно блоки в самом Arrow: https://github.com/arrow-kt/arrow/tree/main/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations (Формально для nullable есть и просто ?. но да, такие блоки помощнее) Для листов иногда хочется в задачах для условного Advent of Code (кстати начался, да), в реальных задачах как-то не сложилось с нуждой лично у меня 🤷♀️ Всякие промисоподобные вещи не особо казалось удобным (но тут можно поспорить, да), у реактивщины вроде нету никакого одного flatMap, чтобы так делать Короче какие-то обходные пути и сейчас есть (раньше в Arrow и для листов вроде был, так что наверное и это можно вернуть). Может что-то для упрощения работы с тем же Result/Either было бы приятно иметь из коробки, но непонятно как лучше, как в условном хаскеле/скале или как-то иначе
Посмотрите, как сделано в Arrow: https://arrow-kt.io/docs/0.10/patterns/monad_comprehensions/. Вот пример кода val university: IO<University> = IO.fx { val (student) = getStudentFromDatabase("Bob Roxx") val (university) = getUniversityFromDatabase(student.universityId) val (dean) = getDeanFromDatabase(university.deanId) dean } честно говоря, не вижу причины, зачем ду-нотацию тащить в язык, если её можно реализовать на уровне библиотеки с помощью корутин.
Кстати, а насколько оно эффективно в байт-коде? Там от рантайма корутин ничего не остаётся, или оно наоборот на него завязано?
Оно не зависит от kotlinx.coroutines. Единственное, что от корутин требуется - это продолжения. А они оптимизированы донельзя. Плюс на всю цепочку аллоцируется только одно продолжение, а не по лямбде на каждый шаг, если делать через дешугаринг.
Любопытно, спасибо! Вот, ещё один козырь в крышку гроба ду-нотации а котлине.
А разве там не было истории о том, что эрроу использует корутины не так, как вы предполагали, потому вы не можете обещать, что вы их не сломаете? :)
Намерено ломать эрроу мы не планируем. И сейчас если ломать корутины, то это будет несовместимое изменение. А на это нужны ооочень веские причины. Так что, вероятность, что мы сломаем эрроу - минимальная.
Кажется надо проголосовать, чтобы это не приняли 😂
Обсуждают сегодня