… Traverse F[A] using Applicative[G]. A values will be mapped into G[B] and combined using Applicative#map2. This method is primarily useful when G[_] represents an action or effect, and the specific A aspect of G[A] is not otherwise needed. def traverse_[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = override def update(userId: UserId, cart: Cart): F[Unit] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap => itemIdToQuantityMap.toList.traverse_ { case (itemId, _) => ID.read[F, ItemId](itemId).flatMap { id => cart.items.get(id).traverse_ { quantity => redis.hSet(userId.show, itemId, quantity.show) } } } } *> redis.expire(userId.show, exp.value).void override def update(userId: UserId, cart: Cart): F[Unit] = redis.hGetAll(userId.show).flatMap { itemIdToQuantityMap => itemIdToQuantityMap.toList.traverse_ { case (itemId, _) => ID.read[F, ItemId](itemId).flatMap { id => cart.items.get(id).traverse_ { quantity => redis.hSet(userId.show, itemId, quantity.show) } } } } *> redis.expire(userId.show, exp.value).void List[(String,String)] => ((String,String) => F[Unit]) => F[Unit] def make[F[_]: GenUUID: MonadThrow] type MonadThrow[F[_]] = MonadError[F, Throwable] An applicative that also allows you to raise and or handle an error value. This type class allows one to abstract over error-handling applicatives. trait ApplicativeError[F[_], E] extends Applicative[F] { … This type class allows one to abstract over error-handling monads. trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] { … Applicative Monad Functor ApplicativeError MonadError Traverse Foldable scala> import cats.implicits._, cats.effect.IO, cats.effect.unsafe.implicits.global scala> :type List("snap", "crackle", "pop").traverse_(IO.println) cats.effect.IO[Unit] scala> List("snap", "crackle", "pop").traverse_(IO.println).unsafeRunSync snap crackle pop ^⇧P Type Info