List to multiple anonymous/underscore parameters in for-comprehension - scala

I'm kind of new to Scala/functional so I'm not yet able to use technical language.
I'm experiencing problems with a for-comprehension
val queries =
for {
_ <- createBanco
_ <- createBancoMedio
bankInsertions <- Update[Banco](insertStr).updateMany(NonEmptyList.fromList(createBankList(1, maxBanks)).get)
mediumInsertions <- Update[BancoMedio](mediumInsert).updateMany(NonEmptyList.fromList(mediumList).get)
bankCount <- BancoStatements.getCount().unique
bankGetIds <- BancoStatements.getIds(0, maxBanks).to[List]
bankSome <- BancoStatements.getSome(halfBanks).to[List]
} yield (bankCount, bankGetIds, bankSome)
//Execute database queries, saves them on tuple
val transactionResults : (Int, List[String], List[Banco]) =
queries.transact(h2Transactor).unsafeRunSync()
I'm trying to refactor the _ <- createBanco & _ <- createBancoMedio, which are both a ConnectionIO[Int] object.
Id like to convert those to a single List(createBanco, createBancoMedio) and then execute transact.
However, i'd be altering the return type of the for-comprehension by doing that. I'd like to know if there is any way on doing that without affecting the for output value
Basically, treat the list as if I was writing multiple anonymous parameters manually.

You can use .sequence to turn a List[G[A]] into a G[List[A]] if G has an Applicative instance, which ConnectionIO does:
val queries =
for {
_ <- List(createBanco, createBancoMedio).sequence
...

Just solved it, did another for comprehension for the List
val createList = for {
m <- createBancoMedio
b <- createBanco
} yield List(b, m)
val queries =
for {
_ <- createList ....
This way i had a ConnectionIO[List[Int]]

Related

Difference between parSequence and starting fibers manually

I have got two program's implementatnion
def program_valid: IO[Unit] = for {
interpreter <- Interpreter[IO]
fib1 <- display(interpreter).start
fib2 <- read(interpreter).start
_ <- fib1.join
_ <- fib2.join
} yield ()
def program_invalid: IO[Unit] = for {
interpreter <- Interpreter[IO]
_ <- (read(interpreter), display(interpreter)).parSequence
} yield ()
First one works perfectly well which means both fibers keep running (dispaly and read). Unfortunately second implementatnion works different. It looks like only the display fiber would run. Why it goes like that? What is the difference here?
parSequence is for collections (well actually for types with an instance of Traverse), not sure how it even compiles; well I mean there is probably a Traverse instance for Tuple2 but it definitively doesn't do what you want.
You may use:
_ <- (read(interpreter), display(interpreter)).parTupled.void
// Or
_ <- IO.both(read(interpreter), display(interpreter)).void
// Or
_ <- read(interpreter).both(display(interpreter)).void
// Or
_ <- List(read(interpreter), display(interpreter)).parSequence_

How to combine 2 future sequences of type Seq[Either[A,B]]?

Suppose,there are 2 future sequences of type Future[Seq[A,B]]. How can I combine into one?
You combined Futures using flatMap. So like:
futureA.flatMap(firstSequence =>
futureB.map(secondSequence => firstSequence ++ secondSequence))
For comprehensions are syntax sugar for this:
for {
firstSequence <- futureA
secondSequence <- futureB
} yield firstSequence ++ secondSequence
This code will run your Futures sequentially if they've been lazy up until this point. So you may wish to allow them to run in parallel by assigning them to a val before the for comprehension.
val executingFutureA = futureA
val executingFutureB = futureB
for {
firstSequence <- executingFutureA
secondSequence <- executingFutureB
} yield firstSequence ++ secondSequence
You can use Future.sequence to convert a sequence of Future into a single Future containing a sequence of the results of each Future. So in your case you can do this:
val a: Future[Seq[Either[A,B]]] = ???
val b: Future[Seq[Either[A,B]]] = ???
Future.sequence(Seq(a, b)).map(_.flatten) // => Seq[Either[A,B]]
The flatten operations converts the Seq[Seq[Either[A,B]]] into Seq[Either[A,B]], but the results could be combined in other ways if required.
This solution is very flexible, but for a fixed number of Seq[Future] it is often better to use flatMap/for as explained in another answer.

Yield after if within nested for loop

I'm having trouble with a nested for loop and using yield properly.
The problem is if I have two lists of the form List[(Int,Int)]
val ls = (1,5)::(3,2)::(5,3)::Nil
val ls_two = (1,9)::(5,9)::(6,7)::Nil
and now I want to create a third list only combining the key and both second int of all the lists so the result would be
val result = (1,5,9)::(5,3,9)::Nil
I've tried a few variations of something like this which none seem to work
val result = for(i <- ls) {
for(j <- ls_two) {
if(i._1 == j._1) yield (i._1,i._2,j._2)
}
}
I've tried placing the yield at the end of the for loop, it seems to work if i replace yield with println but i'm not sure how to do it with yield.
Also if you have a more functional approach to how to solve this it would be greatly appreciated, thanks!
The recommended approach here is not to "nest" the "loops" at all - but to create a single for-comprehension which uses a "guard":
val result = for {
i <- ls
j <- ls_two if i._1 == j._1
} yield (i._1,i._2,j._2)

Future[Option[Boolean]] in a for comprehension.. Simple right?

Suppose I have:
val res:Future[Option[Boolean]] = Future(Some(true))
and I can do:
res.map(opt => opt.map(r => print(!r)))
I guess the for comprehension for this would be:
for {
opt <- res
r <- opt
} yield (print(!r))
but this does not work! I get an error ie:
error: type mismatch;
found : Option[Unit]
required: scala.concurrent.Future[?]
r <- opt
How do I use a Future[Option[Boolean]] in a for comprehension to extract or convert the Boolean?
Note: this is a simplification of the problem I have at the moment with many Future[Option[Boolean]] variables that I would like to use together in a for comprehension.
A for-comprehension really makes this look like it should all work, doesn't it? But let's think about what you're asking for.
First, note that for un-nests:
for {xs <- List(List(5)); x <- xs} yield x
produces
List(5)
Now, without even getting into the type signatures or desugaring, we can think about replacing List with some arbitrary type T, and we'll call the contained type A:
for { xs <- T(T(a: A)); x <- xs } yield x
and we should get a
T[A]
back (presumably the one we put in, but the types don't actually promise us that).
Okay, but what about
for { xs <- T(U(a: A)); x <- xs } yield x
? This is strictly more general than the case where the two things have the same nesting. Well, if T and U both have a common supertype S, then we can just view the whole thing as S(S(a: A)), so we'll at least get an S back. But what about in the general case?
The bottom line is that it depends. For example, let's consider the case where T=Future, U=Option. We have the following possibilities:
Success(Some(a))
Success(None)
Failure(t: Throwable)
Now, can we come up with any coherent policy for unwrapping? If we unwrap into a Future, then what A do you use for the Success(None) case? You don't have one available to return. Likewise, if you try to vanquish the outer Future, how do you know, without explicitly stating it somehow to the compiler, that Failure should be mapped to None (if indeed it should--maybe it should go to a default!).
So the bottom line is that you just can't do this correctly in general without specifying what is supposed to happen for every pair T[U[_]]. (I encourage the interested reader to peruse tutorials on monads and monad transformers.)
There is a way out, though: if you can explicitly turn your U into a T, or your T into your U, you can take advantage of the unwrapping capability. It's pretty easy to turn an Option into a Future , so the easiest solution is
for { opt <- res; r <- Future(opt.get) } yield r
(where just let the exception get thrown on none.get). Alternatively, you can turn the Future into an Option with the slightly ugly
for { opt <- res.value.flatMap(_.toOption); r <- opt } yield r
Equivalent code for
for {
opt <- res
r <- opt
} yield (print(!r))
is not
res.map(opt => opt.map(r => print(!r)))
but
res.flatMap(opt => opt.map(r => print(!r)))
And it makes no sense in this case.
For the chain of maps you could use nested for-comprehensions
for { opt <- res }
for { r <- opt }
print(!r)
But map looks better.
Well, for comprehensions are deceiving in the way they look. Your for-comprehension expands to:
res.flatMap(opt => opt.map(r => print(!r))
Which is obviously wrong as flatMap expects a return type of Future[T] and you are providing Option[Unit]
Though sometimes, for code tidiness you would want to have a single for loop with many such expressions. In those cases you could:
scala> implicit def toFuture[T](t: => T):Future[T] = {
| val p = Promise[T]()
| p.tryComplete(Try(t))
| p.future
| }
scala> for {
| opt <- res
| r <- opt
| } yield {print(!r)}
false
The above produces:
res.flatMap[Option[Unit]](((opt: Option[Boolean]) =>
toFuture[Option[Unit]](opt.map[Unit](((r: Boolean) => print(!r))))))
Edit: Though you need to take all the pain if you are using yield. If you do not wish to use for comprehension as an expression, then you can do as you desired:
scala> val i = Future(Some(true))
i: scala.concurrent.Future[Some[Boolean]] = scala.concurrent.impl.Promise$DefaultPromise#6b24a494
scala> val j = Option(1)
j: Option[Int] = Some(1)
scala> val k = Right(1).right
k: scala.util.Either.RightProjection[Nothing,Int] = RightProjection(Right(1))
scala>
| for{
| x <- i
| y <- j
| z <- k
| }{
| println(i,j,k)
| }
(scala.concurrent.impl.Promise$DefaultPromise#6b24a494,Some(1),RightProjection(Right(1)))
This way no implicit is required. As compiler uses foreach at every junction. -Xprint:typer gives:
i.foreach[Unit](((x: Option[Boolean]) =>
j.foreach[Any](((y: Int) =>
k.foreach[Unit](((z: Int) => println(scala.this.Tuple3.apply[scala.concurrent.Future[Option[Boolean]], Option[Int], Either.RightProjection[Nothing,Int]](i, j, k))))))))
}

Scala Option return type

I am newbie in Scala programming world but loving it. Recently I have started porting my research App into Scala and one of thing I am still struggling is the return keyword. For example in below code
def readDocument(dbobj:MongoDBObject) = Option[ContainerMetaData]
{
for(a <- dbobj.getAs[String]("classname");
b <- dbobj.getAs[Long]("id");
c <- dbobj.getAs[Long]("version");
d <- dbobj.getAs[String]("description");
e <- dbobj.getAs[String]("name");
f <- dbobj.getAs[String]("tag");
g <- dbobj.getAs[Int]("containertype");
h <- dbobj.getAs[Date]("createddate")
)
{
val ctype = ContainerType(g)
val jodadt = new DateTime(h)
val data = new ContainerMetaData(a,b,c,d,e,f,ctype,jodadt)
Some(data)
}
None
}
In above code I get the error message:
type mismatch; found : None.type required: om.domain.ContainerMetaData
So if I remove the explicit return type the code works but then without explicit return keyword I am not able to terminate my code at Some(data).
def readDocument(dbobj:MongoDBObject)=
{
for(a <- dbobj.getAs[String]("classname");
b <- dbobj.getAs[Long]("id");
c <- dbobj.getAs[Long]("version");
d <- dbobj.getAs[String]("description");
e <- dbobj.getAs[String]("name");
f <- dbobj.getAs[String]("tag");
g <- dbobj.getAs[Int]("containertype");
h <- dbobj.getAs[Date]("createddate")
)
{
val ctype = ContainerType(g)
val jodadt = new DateTime(h)
val data = new ContainerMetaData(a,b,c,d,e,f,ctype,jodadt)
Some(data)
}
None
}
And if add a return keyword then compiler complains
method `readDocument` has return statement; needs result tye
Few more additional info, this is the trait I am extending
trait MongoDAOSerializer[T] {
def createDocument(content:T) : DBObject
def readDocument(db:MongoDBObject) : Option[T]
}
The problem is, that you are missing the yield keyword in the for-comprehension. And also the None at the end is unnecessary, as the for-comprehension will yield None, if one of the values is missing and also the explicit creation of a Some in the comprehension is not needed, as it will create an Option anyway. Your code hase to look like this (not tested)
def readDocument(dbobj: MongoDBObject): Option[ContainerMetaData] = {
for {
a <- dbobj.getAs[String]("classname")
b <- dbobj.getAs[Long]("id")
c <- dbobj.getAs[Long]("version")
d <- dbobj.getAs[String]("description")
e <- dbobj.getAs[String]("name")
f <- dbobj.getAs[String]("tag")
g <- dbobj.getAs[Int]("containertype")
h <- dbobj.getAs[Date]("createddate")
} yield {
val ctype = ContainerType(g)
val jodadt = new DateTime(h)
new ContainerMetaData(a,b,c,d,e,f,ctype,jodadt)
}
}