Combine IO and State Monad in Scalaz - scala

I am attempting to write a simple program using the State monad in scalaz that will modify some state based on input passed in by the user. How is the best accomplished. Currently I have:
import scalaz._
import Scalaz._
import effect._
import IO._
def acc = for {
i <- init
_ <- modify{s: Int => 100}
v <- readLn
_ <- modify{s: Int => v}
} yield ()
which throws:
<console>:25: error: polymorphic expression cannot be instantiated to expected type;
found : [B]scalaz.effect.IO[B]
required: scalaz.IndexedStateT[scalaz.Id.Id,Int,?,?]

You can't do this directly, but the monad transformer version isn't too terrible:
import scalaz._, Scalaz._, effect._, IO._
type IS[S, A] = StateT[IO, S, A]
type ISInt[A] = IS[Int, A]
val ms = MonadState[IS, Int]
import ms._
def acc = for {
i <- init
_ <- modify(s => 100)
v <- readLn.liftIO[ISInt]
_ <- modify(s => v.toInt)
} yield ()
This gives you a StateT[IO, Int, Unit] that you can turn into an IO action with acc.exec(whatever).
It's worth noting your code could be cleaned up a bit—the init is unnecessary, for example, and you might as well use put if you're throwing away the arguments in modify, etc. It's also worth noting that in practice something like an IORef might be more practical here.

Related

Zio, transform Seq[ZIO] to ZIO[Seq]

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.
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
}
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:
typelevel documentation cats.Traverse
typelevel documentation cats.Applicative
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
)

Avoiding boilerplate with OptionT (natural transform?)

I have the following methods:
trait Tr[F[_]]{
def getSet(): F[Set[String]]
def checksum(): F[Long]
def value(): F[String]
def doRun(v: String, c: Long, s: Set[String]): F[Unit]
}
now I want to write the following for comprehension:
import cats._
import cats.data.OptionT
import cats.implicits._
def fcmprhn[F[_]: Monad](F: Tr[F]): OptionT[F, Unit] =
for {
set <- OptionT {
F.getSet() map { s =>
if(s.nonEmpty) Some(s) else None
}
}
checksum <- OptionT.liftF(F.checksum())
v <- OptionT.liftF(F.value())
_ <- OptionT.liftF(F.doRun(v, checksum, set))
//can be lots of OptionT.liftF here
} yield ()
As you can see there is too much of OptionT boilerplate. Is there a way to avoid it?
I think I can make use of F ~> OptionT[F, ?]. Can you suggest something?
One approach could be to nest the "F only" portion of the for-comprehension within a single liftF:
def fcmprhn[F[_]: Monad](F: Tr[F]): OptionT[F, Unit] =
for {
set <- OptionT {
F.getSet() map { s =>
if(s.nonEmpty) Some(s) else None
}
}
_ <- OptionT.liftF {
for {
checksum <- F.checksum()
v <- F.value()
_ <- F.doRun(v, checksum, set)
// rest of F monad for-comprehension
} yield ()
}
} yield ()
You can write it in "mtl-style" instead. mtl-style refers to mtl library in haskell but really it just means that instead of encoding effects as values (i.e. OptionT[F, ?]), we encode them as functions that take an abstract effect F[_] and give that F capabilities using type classes. That means instead of using OptionT[F, Unit] as our return type we can just use F[Unit] as our return type because F has to be able to handle errors.
This makes writing code like yours a small bit easier, but it's effect is amplified as you add monad transformers to the stack. Right now you only have to lift once, but what if you wanted a StateT[OptionT[F, ?], S, Unit] in the future. With mtl-style, all you need to do is add another type class constraint.
Here's what your code'd look like written in mtl-style:
def fcmprhn[F[_]](F: Tr[F])(implicit E: MonadError[F, Unit]): F[Unit] =
for {
set <- OptionT {
F.getSet() flatMap { s =>
if(s.nonEmpty) E.pure(s) else E.raiseError(())
}
}
checksum <- F.checksum()
v <- F.value()
_ <- F.doRun(v, checksum, set)
} yield ()
And now when you run the program you can specify the F[_] to be something like what you had before OptionT[F, ?]:
fcmprhn[OptionT[F, ?]](OptionT.liftF(yourOriginalTr))

How to compose validation, disjunction and futures properly

I have to call 2 functions, the first one is returning a \/[String, Int], the other one is returning a Future[Int].
I need to accumulate the validation of this 2 function calls.
Here is my attempt :
import scala.concurrent.Future
import scalaz._, Scalaz._, Validation._
import scala.concurrent.ExecutionContext.Implicits.global
def positive(x: Int): \/[String,Int] = if(x<0) "ko".left else x.right
def inc(x: Int): Future[Int] = if (x >5) Future.successful(x +1) else Future.failed(new Exception("failed"))
def eval(x:Int, y:Int): Future[Validation[String, (Int, Int)]] = for {
v1 <- Future.successful(positive(x).validation)
v2 <- inc(y).map(x => success(x)).recover{case ex: Exception => failure(ex.getMessage)}
} yield ((v1 |#| v2){(_,_)})
) Is there a simpler way to do this, to avoid manual biding of future errors to success/failure?
2) I'd like to use ValidationNel to accumulate error messages (right now I retrieve messages like "Failure(kofailed)" with just a concatenation of the 2 messages) but I don't know if it's possible to get a ValidationNel from a \/ type.

Scala Future[Option[T]] Un Packing

In the following snippet,
trait MyType1; trait MyType2
import scala.concurrent.Promise
val p1 = Promise[Option[MyType1]]()
val p2 = Promise[MyType2]()
I pass in p1 and p2 to another function where I complete the Promise using a successful Future. After the call to this function, I try to read the value in the Promise:
trait Test {
// get the Future from the promise
val f1 = p1.future
val f2 = p2.future
for {
someF1Elem <- f1
f1Elem <- someF1Elem
f2Elem <- f1Elem
} yield {
// do something with f1Elem and f2Elem
"..."
}
}
When I try to compile this, I get some compiler issues.
Error:(52, 19) type mismatch;
found : Option[Nothing]
required: scala.concurrent.Future[?]
flElem <- someF1Elem
^
IntelliJ shows no errors or what-so-ever and the types look aligned. But I'm not sure why the compiler is unhappy! Any clues?
Your for comprehension types must be consistent, so you cannot freely mix Option and Future in the way you do.
In your example, f1 returns a Future[Option[MyType1]] while f2 returns a Future[MyType2]
Remember that a for comprehension desugars to a series of flatMap/map and potentially withFilter.
Also the (simplified) signatures of flatMap for Future[A] and Option[A] are
def flatMap[B](f: A => Future[B]): Future[B]
def flatMap[B](f: A => Option[B]): Option[B]
The first two steps of the for-comprehension desugar to
f1.flatMap { someF1Elem =>
someF1Elem.flatMap { f1Elem => // this returns a `Option[MyType1]`
...
}
}
see the error now?
Now, to fix this there's a few approaches you can follow. One very handy is to use Monad Transformers, which allow you to combine (for instance) Future and Option into a single monad type OptionT.
Specifically you can go back and forth from Future[Option[A]] to OptionT[Future, A]. The basic idea is that you can flatMap on the latter and extract a value of type A.
But before that, you need to make your types of the "right shape", so that both are a Future[Option[Something]]
Here's an example using scalaz
import scalaz._; import Scalaz._ ; import scalaz.OptionT._
import scala.concurrent.{ Promise, Future }
import scala.concurrent.ExecutionContext.Implicits.global
trait MyType1
trait MyType2
val p1 = Promise[Option[MyType1]]()
val p2 = Promise[MyType2]()
val f1 = p1.future
val f2 = p2.future
val res = for {
f1Elem <- optionT(f1)
f2Elem <- f2.liftM[OptionT]
} yield {
println(s"$f1Elem $f2Elem")
}
optionT builds an OptionT[Future, A] given a Future[Option[A]], while liftM[OptionT] achieves the same when you have a Future[A]
The type of res is OptionT[Future, Unit] in this case, and you can get a Future[Option[Unit]] by calling run on it.
Looking at "How does yield work", your for comprehension is equivalent to
f1.flatMap(someF1Elem: Option[MyType1] =>
someF1Elem.flatMap(f1Elem =>
f1Elem.map(f2Elem =>
"..."
)
)
)
Basically what happens is this: flatMap on a Future is defined to take a function that returns another Future.
This gives you a similar error:
<console>:64: error: value map is not a member of MyType1
f1Elem.map(f2Elem =>
^
<console>:63: error: type mismatch;
found : Option[Nothing]
required: scala.concurrent.Future[?]
someF1Elem.flatMap(f1Elem =>
^
If you want the operation to perform asynchronously, i.e. really mapping the Future instances, you will have to get back to a Future[Option[X]]. As Kim suggested, you can nest the comprehension:
import scala.concurrent.{Future, Promise}
def test: Future[Option[String]] = {
val p1 = Promise[Option[MyType1]]()
val p2 = Promise[MyType2]()
// ... run code that completes the promises
val f1 = p1.future
val f2 = p2.future
for {
someF1Elem: Option[MyType1] <- f1
f2Elem <- f2
} yield {
for (f1Elem <- someF1Elem) yield "something"
}
}
You could also make the resulting Future fail when the option is not defined (NoSuchElementException)
def test: Future[String] = {
val p1 = Promise[Option[MyType1]]()
val p2 = Promise[MyType2]()
// ... run code that completes the promises
val f1 = p1.future
val f2 = p2.future
for {
someF1Elem: Option[MyType1] <- f1
f2Elem <- f2
} yield {
val f1Elem = someF1Elem.get // may cause an exception and fail the future
"something"
}
}
In a for comprehension, the expressions on the right hand side of the <- have to have compatible types. That is because for comprehensions are basically syntactic sugar for nested flatMap calls. To solve this problem, you can either have a for comprehension nested within another for comprehension or you can use methods like get or map on the Options.
Another option is to use monad transformers, but that's beyond the scope of this answer.

Iterable[Try[(K, V)]] to Try[Map[K, V]]

I have a method load which is relatively expensive to call. In order to allow some kind of exception handling during loading it returns a Try. I need now an implementation for the loadAll method which basically delegates to load for each of the given keys. Here is my first approach, however I don't know if this is best practices with respect to the work with Try. Is there a better way to achieve the following?
def load(key: K): Try[V] // very expensive
def loadAll(keys: Traversable[K]): Try[Map[K, V]] = {
// remove duplicate keys
val ukeys = Set.empty ++ keys
val result: Iterable[Try[(K, V)]] = ukeys map { key =>
load(key) match {
case Success(value) => Success(key, value)
case Failure(exception) => Failure(exception)
}
}
Try(result.map { _.get }.toMap)
}
You can do this using a fold to iterate over the keys, and a for comprehension to combine the Try instances:
def toSet(keys: Traversable[K]): Try[Map[K, V]] = {
keys.toSet.foldLeft( Try( Map.empty[K, V] ) ){ case (tryMap, key) =>
for ( m <- tryMap; v <- load( key ) ) yield m.updated( key, v )
}
}
It's a one-liner in vanilla Scala (assuming you've already got Try in scope):
def loadAll(keys: Traversable[K]) = Try{ keys.toSet.map((k: K) => (k,load(k).get)).toMap }
If you're interested in a scalaz solution, this is a general operation, available via Traversable functors, called sequence. Needed instances for Try reside in scalaz-contrib. Here's how it might look like:
Welcome to Scala version 2.10.1 (OpenJDK 64-Bit Server VM, Java 1.7.0_21).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scalaz._, Scalaz._, scalaz.contrib.std.utilTry._
import scalaz._
import Scalaz._
import scalaz.contrib.std.utilTry._
scala> import scala.util.Try
import scala.util.Try
scala> val result: Iterable[Try[(Int, String)]] = Iterable.empty
result: Iterable[scala.util.Try[(Int, String)]] = List()
scala> result.toList.sequence.map(_.toMap)
res0: scala.util.Try[scala.collection.immutable.Map[Int,String]] = Success(Map())
By the way, there's a paper "The essence of the Iterator pattern", describing/deriving traverse (and sequence, as it's special case). There's a great summary of this paper by Eric Torreborre here.