Reputation: 2347
That may be a dumb question, but starting with ZIO, I cannot manage to convert a Seq[ZIO]
to ZIO[Seq]
:
def translate(keys: Seq[String], locales: Seq[Locale]):RIO[Translator, Seq[Translation]] = {
for {
service <- ZIO.environment[Translator]
} yield {
// service.translate produce a zio.Task[Translation]
keys.map(k => service.translate(k, locales)
}
}
Required: RIO[Translator, Seq[Translation]]
Found : ZIO[Translator, Nothing, Seq[zio.Task[Translation]]
I tried flatMap
, flatten
, collectAll
and merge
but I was not able to get the expected result with anyone.
How can I transform a Seq[ZIO[_, _, B]]
to a ZIO[_, _, Seq[B]]
?
Thanks
Edit: It seems that ZIO.foreach
is the best option, however I still have it wrapped inside another ZIO due to the for comprehension.
Upvotes: 3
Views: 2582
Reputation: 449
To "exchange" List and ZIO you could dance this way:
def dance(x: List[ZIO[Any,Throwable,Int]]): ZIO[Any, Throwable, List[Int]] =
x.map ( a => a.map(x=> List(x)))
.fold ( ZIO.succeed( List[Int]()) )
((x, y) => x.map(a => y.map(b => a ++ b ) )
.flatten
)
Upvotes: 0
Reputation: 4585
Because for loops translate to flatMap
except for the last line which is a map
, you want to add the foreach
call within the for-loop.
def translate(keys: Seq[String], locales: Seq[Locale]): RIO[Translator, Seq[Translation]] = {
for {
translator <- ZIO.environment[Translator]
translations <- ZIO.foreach(keys)(translator.translate(_, locales))
} yield translations
}
Upvotes: 11
Reputation: 4491
If I got you right you can do it using traverse
function from cats
:
import cats.instances.list._
import cats.syntax.traverse._
import zio.{RIO, Task, ZIO}
import zio.interop.catz._
import java.util.Locale
case class Translation()
trait Translator {
def translate(k: String, locales: Seq[Locale]): Task[Translation]
}
def translate(keys: Seq[String], locales: Seq[Locale]): RIO[Translator, Seq[Translation]] = {
val translator: Translator = ???
for {
service <- ZIO.effect(translator)
result <- keys.toList.traverse(k => service.translate(k, locales))
} yield result
}
For map List[ZIO[_, _, B]]
to ZIO[_, _, List[B]]
you can use sequence
function and I would advice to use cats
library for that.
import zio.ZIO
import zio.interop.catz._
import cats.syntax.traverse._
import cats.instances.list._
def ziosSequence[B](seqZIO: Seq[ZIO[Any, Throwable, B]]): ZIO[Any, Throwable, Seq[B]] =
seqZIO.toList.sequence.map(_.toSeq)
the sequence
signature is:
def sequence[G[_]: Applicative, A](fga: F[G[A]]): G[F[A]] =
traverse(fga)(ga => ga)
Here we see what function do what we need.
it requires Applicative
instance for G
(G
is ZIO
in your case), and we just import it using import zio.interop.catz._
Also, to make list is able to call sequence
we need import Traverse
instance for List
:
by import cats.instances.list._
Unfortunetaly we can not do the same tricks with Seq
because we need Traverse
instance for sequence
, and we should convert Seq
to List
back and forth before and after sequence
.
useful links:
Upvotes: 1