Где реализация Traverse[IO]

val foo: IO[List[Int]] = List(IO.pure(100)).sequence

Где я могу найти реализацию метода sequence? Я предполагаю, что для cats.effect.IO существует реализация класса типов Traverse, и где я могу найти эту реализацию? Если я ошибаюсь, как работает foo выше? Спасибо

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Для Traverse нет IO, ну, я думаю, что нет, и если он есть, это не относится к этому примеру.
Однако существует Traverse для List и Applicative для IO, и поскольку IO также образует Monad, то этот делегат для flatMap.

В общем, мы знаем, что:

def sequence[A, F[_], G[_]](fga: F[G[A]])(using Traverse[F], Applicative[G]): G[F[A]] =
  traverse(fga)(identity)

trait Traverse[F[_]]:
  def traverse[A, B, G[_]](fa: F[A])(f: A => G[B])(using Applicative[G]): G[F[B]]

А для List реализация traverse следующая:

given Traverse[List] with
  override def traverse[A, B, G[_]](fa: List[A])(f: A => G[B])(Applicative[G]): G[List[B]] =
    fa.foldLeft(Appliative[G].pure(List.empty[B])) {
      case (accG: G[List[B]], a: A) =>
        val gb: G[B] = f(a)
        Appliative[G].map2(accG, gb) {
           case (acc: List[B], b: B) =>
             b :: acc
        }
    }.map(_.reverse) // Or you could use foldRight or another more optimal strategy but that is besides the point.

А еще мы знаем, что когда есть Monad[G], то:

trait Monad[G[_]] extends Applicative[G]:
  override def map2[A, B, C](ga: G[A], gb: G[B])(f: (A, B) => C): G[C] =
    for
      a <- ga
      b <- gb
      c = f(a, b)
    yield c

Другими словами, это становится просто обходом List с использованием flatMaps.


Соответствующие источники:

Реальные реализации, конечно, более оптимизированы и немного сложнее, чем те, которые я использовал. Но концептуально они эквивалентны.

Спасибо за подробное объяснение

thlim 13.04.2024 07:32

Я добавлю к ответу Луиса, что вы всегда можете увидеть, как разрешаются неявные выражения, например, с помощью scalacOptions += "-Vprint:typer"

Можно ли в scala 2 или 3 отлаживать процесс неявного разрешения во время выполнения?

Для

val foo: IO[List[Int]] = List(IO.pure(100)).sequence

это печатает

https://scastie.scala-lang.org/CD03j1FTSzGK61i5UivDRg

//val foo: cats.effect.IO[List[Int]] = cats.syntax.`package`.traverse.toTraverseOps[List, cats.effect.IO[Int]](scala.`package`.List.apply[cats.effect.IO[Int]](cats.effect.IO.pure[Int](100)))(cats.UnorderedFoldable.catsTraverseForList).sequence[cats.effect.IO, Int](scala.<:<.refl[cats.effect.IO[Int]], cats.effect.IO.asyncForIO);

Итак, он обессахарен, как

val foo: IO[List[Int]] = cats.syntax.traverse.toTraverseOps[List, cats.effect.IO[Int]](
    scala.List.apply[cats.effect.IO[Int]](cats.effect.IO.pure[Int](100))
  )(cats.UnorderedFoldable.catsTraverseForList)
  .sequence[cats.effect.IO, Int](scala.<:<.refl[cats.effect.IO[Int]], effect.IO.asyncForIO)

Итак, экземпляр Traverse (Traverse[List]) — это cats.UnorderedFoldable.catsTraverseForList, а экземпляр Applicative (Applicative[IO]) — это cats.effect.IO.asyncForIO.

Эти экземпляры (Traverse[List], Applicative[IO]) — это то, что вам нужно, чтобы преобразовать List[IO[A]] в IO[List[A]]. Экземпляры Traverse[IO], Applicative[List] понадобятся, если вы наоборот захотите преобразовать IO[List[A]] в List[IO[A]].

Посмотрите, почему нет экземпляра Traverse[IO]Foldable[IO]): Можно ли секвенировать файл Cats.effect.IO, т. е. находится ли он в классе типов Traverse?

Другие вопросы по теме