169 похожих чатов

Привет! Есть вопросик к коммьюнити: Кто-нибудь хотел бы иметь в котлине что-то

вроде 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

10 ответов

51 просмотр

По-моему это ужасно. Вообще не понятно, что оно делает. Не говоря о том, что пример плохой, если у вас там там что-то типа 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 } честно говоря, не вижу причины, зачем ду-нотацию тащить в язык, если её можно реализовать на уровне библиотеки с помощью корутин.

Alexander-Bashkirov Автор вопроса
Ilmir
Посмотрите, как сделано в Arrow: https://arrow-kt....

Кстати, а насколько оно эффективно в байт-коде? Там от рантайма корутин ничего не остаётся, или оно наоборот на него завязано?

Alexander Bashkirov
Кстати, а насколько оно эффективно в байт-коде? Та...

Оно не зависит от kotlinx.coroutines. Единственное, что от корутин требуется - это продолжения. А они оптимизированы донельзя. Плюс на всю цепочку аллоцируется только одно продолжение, а не по лямбде на каждый шаг, если делать через дешугаринг.

Alexander-Bashkirov Автор вопроса
Ilmir
Оно не зависит от kotlinx.coroutines. Единственное...

Любопытно, спасибо! Вот, ещё один козырь в крышку гроба ду-нотации а котлине.

Ilmir
Оно не зависит от kotlinx.coroutines. Единственное...

А разве там не было истории о том, что эрроу использует корутины не так, как вы предполагали, потому вы не можете обещать, что вы их не сломаете? :)

Andrew Mikhaylov
А разве там не было истории о том, что эрроу испол...

Намерено ломать эрроу мы не планируем. И сейчас если ломать корутины, то это будет несовместимое изменение. А на это нужны ооочень веские причины. Так что, вероятность, что мы сломаем эрроу - минимальная.

Кажется надо проголосовать, чтобы это не приняли 😂

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
вы делали что-то подобное и как? может есть либы готовые? увидел картинку нокода, где всё линиями соединено и стало интересно попробовать то же в ddl на lua сделать. решил с ч...
Victor
8
Подскажите пожалуйста, как в CustomDrawCell(Sender: TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean); получить наз...
A Z
7
Ребят в СИ можно реализовать ООП?
Николай
33
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
1
Он в одиночку это дело запилил или была какая-то команда?
Aquinary
12
~ 2m21s  nix shell github:nixos/nixpkgs#stack ~  stack ghc -- --version error: … while calling the 'derivationStrict' builtin at /builtin/derivation.nix:...
Rebuild your mind.
6
Всем привет, нужна как никогда, нужна помощь с IO в загрузчике. Пишу в code16 после установки сегментных регистров, пишу вывод символа. Пробовал 2 варианта: # 1 mov $0x0E, %a...
Shadow Akira
14
Карта сайта