Как сгладить понимание с помощью эффекта траверса scala cats?

У меня есть код, структурно идентичный этому, и я не уверен, как лучше его очистить? Существуют тривиальные операции ввода-вывода и дополнения, поэтому пример компилируется без дополнительных методов.

Я бы действительно хотел, чтобы он не был таким вложенным, есть ли способ иметь сингл для понимания, который поддерживает как ввод-вывод, так и список? Я знаю, что существует OptionT для варианта этой проблемы, но похоже, что нет эквивалентного ListT.

Любой совет будет очень признателен

import cats.Traverse
import cats.effect.IO
import cats.implicits._

def exampleDoingSomeThings: IO[Unit] = for {
    ids <- IO.pure(List(1, 2, 3))
    _ <- ids.traverse[IO, Unit](id => for {
      users <- IO.pure(List(id + 4, id + 5, id + 6))
      data <- IO(id + 7)
      otherData <- IO(id + 8)
      _ <- users.traverse[IO, Unit](ud => for {
        innerData <- IO(id + ud)
        innerState <- IO(ud + 9)
        _ <- if (innerState > 15) for {
          _ <- IO(println(s"action1: $id $ud"))
          _ <- IO(println(s"action2: $id $ud"))
        } yield () else IO.pure()
      } yield ())
    } yield ())
  } yield ()

exampleDoingSomeThings.unsafeRunSync

https://scalafiddle.io/sf/S79H1ZI/0


person epigram-engineer    schedule 26.11.2019    source источник
comment
typelevel.org/cats/faq.html#listt   -  person Dmytro Mitin    schedule 26.11.2019
comment
Как насчет извлечения внутренних частей более мелкими методами? Таким образом, вы увидите только один уровень вложенности.   -  person Yuval Itzchakov    schedule 26.11.2019
comment
Да, это то, к чему я пришел. Немного рассеянно, я не могу, чтобы это читалось больше как сплющенное понимание. Спасибо за ссылку на FAQ!   -  person epigram-engineer    schedule 28.11.2019


Ответы (1)


Как уже упоминалось, вы можете извлечь свои методы в подметоды. Однако, если вы обнаружите, что этого недостаточно, вы можете использовать такие библиотеки, как FS2. или Monix, чтобы облегчить вам жизнь. Это действительно хорошо для обработки вещей IO + List.

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

Приведенный выше пример можно перевести как (исключая неиспользуемые переменные):

Моникс:

def monixThings: Observable[Unit] = for {
  id <- Observable.fromIterable(List(1, 2, 3))
  ud <- Observable.fromIterable(List(id + 4, id + 5, id + 6))
  innerState <- Observable.pure(ud + 9)
  _ <- Observable.fromTask {
    if (innerState > 15) {
      for {
        _ <- Task.delay(println(s"action1: $id $ud"))
        _ <- Task.delay(println(s"action2: $id $ud"))
      } yield ()
    } else {
      Task.unit
    }
  }
} yield ()

monixThings.completedL.runSyncUnsafe()

https://scalafiddle.io/sf/BDKbGCq/0

FS2:

import cats.effect.IO
import fs2.Stream

object FS2Example extends App {

  def fs2Things = for {
    id <- Stream.emits(List(1, 2, 3))
    ud <- Stream.emits(List(id + 4, id + 5, id + 6))
    innerState <- Stream.emit(ud + 9)
    _ <- Stream.eval {
      if (innerState > 15) {
        for {
          _ <- IO(println(s"action1: $id $ud"))
          _ <- IO(println(s"action2: $id $ud"))
        } yield ()
      } else {
        IO.unit
      }
    }
  } yield ()

  fs2Things.compile.drain.unsafeRunSync()
}
person atl    schedule 27.11.2019