Effectful update of Ref/MVar - scala

I'd like to apply effectual computation to the value inside MVar or Ref and atomically update it in case the computation succeeds or put back the initial value (in case of MVar)/simply do nothing(in case of Ref) in case the operation fails.
I. Ref-case
val ref = Ref.of[IO, Int](0)
def foo(i: Int): IO[Int] = //... some effectual computation
Since atomicity matters and Ref does not provide compareAndSet operation unfortunately so it must be implemnted explicitly which does not look attracting.
II. MVar-case
MVar provides mutually-exclusion semantic, but the problem is that bracket does not allow us to put the computed value. Here is an example:
val mvar = MVar.of[IO, Int](0)
def foo(i: Int): IO[Int] = IO(i + 1)
for {
mvar <- mvar
i <- mvar.take.bracket(foo)(mvar.put) //puts back 0, not 1
} yield ()
Is there a way to implement such behavior at least for either MVar or Ref?
UPD:
I implemented it with MVar, but it looks rather ugly:
def updateAtomically(mvar: MVar[IO, Int], foo: Int => IO[Int]): IO[Int] = for {
i <- mvar.take
ii <- foo(i).onError{
case t => mvar.put(i)
}
_ <- mvar.put(ii)
} yield ii

You can use MonadError.redeemWith for this:
def updateAtomically(mvar: MVar[IO, Int], foo: Int => IO[Int]): IO[Int] =
for {
i <- mvar.take
ii <- foo(0).redeemWith(_ => IO(i), ii => mvar.put(ii) *> IO(ii))
} yield ii
And then:
import cats.Applicative.ops.toAllApplicativeOps
import cats.effect.{ ExitCode, IO, IOApp }
import cats.effect.concurrent.MVar
object Foo extends IOApp {
def foo(i: Int): IO[Int] = IO(i + 1)
def fooBar(i: Int): IO[Int] = IO.raiseError(new RuntimeException("BOOM"))
def run(args: List[String]): IO[ExitCode] =
(for {
mvar <- MVar.of[IO, Int](0)
res <- updateAtomically(mvar, foo)
_ <- IO(println(res))
} yield res).map(_ => ExitCode.Success)
}
Yields:
1
And:
def run(args: List[String]): IO[ExitCode] =
(for {
mvar <- MVar.of[IO, Int](0)
res <- updateAtomically(mvar, fooBar)
_ <- IO(println(res))
} yield res).map(_ => ExitCode.Success)
Yields:
0

Related

How to return values with nested Reader monads with cats?

Is there a way to avoid calling the "run" method twice and doing it just once from the main method or this is the right way to do it in nested Readers?
case class Dependencies(showService: ShowService, sumService: SumService)
class ShowService {
def show(s: String): IO[Unit] = IO {println(s)}
}
class SumService() {
def sum(a: Int, b: Int): Reader[Dependencies, IO[Int]] = Reader {_ => IO {a + b} }
}
object ModuleA {
def sumAndShow: ReaderT[IO, Dependencies, Unit] = for {
x <- ReaderT[IO, Dependencies, Int] (deps => deps.sumService.sum(10, 10).run(deps))
r <- ReaderT[IO, Dependencies, Unit] (deps => deps.showService.show(x.toString))
} yield r
}
override def run(args: List[String]): IO[ExitCode] = {
val dependencies = Dependencies(new ShowService, new SumService)
ModuleA.sumAndShow.run(dependencies) *> IO(ExitCode.Success)
}
I'm not sure why you choose to define your services this way but if your question is to avoid calling run in sumAndShow you could lift your Reader/IO into ReaderTs with lift/liftF and compose them with a ReaderT.ask:
def sumAndShow: ReaderT[IO, Dependencies, Unit] =
for {
deps <- ReaderT.ask[IO, Dependencies]
x <- deps.sumService.sum(10, 10).lift[IO].flatMap(ReaderT.liftF)
r <- ReaderT.liftF(deps.showService.show(x.toString))
} yield r
Alternative generic implementation with existing typeclass constraints with Cats/Cats Effect, and also how newtype could be used for alternative typeclass instances:
import cats.implicits._
import cats.effect._
import cats.effect.std.Console
import cats.{Semigroup, Show}
import io.estatico.newtype.macros.newtype
object Main extends IOApp {
#newtype case class MInt(value: Int)
object MInt {
implicit val multiplicativeSemigroup: Semigroup[MInt] =
deriving(Semigroup.instance(_ * _))
implicit val show: Show[MInt] = deriving
}
def sumAndShow[F[_]: Console, A: Show: Semigroup](a: A, b: A): F[Unit] =
Console[F].println(a |+| b)
override def run(args: List[String]): IO[ExitCode] =
for {
_ <- sumAndShow[IO, Int](10, 10) //20
//you can also "inject" default/custom typeclass "dependencies" explicitly
_ <- sumAndShow[IO, Int](10, 10)(Console[IO], Show[Int], Semigroup.instance(_ * _)) //100
//custom typeclass instance with newtype
_ <- sumAndShow[IO, MInt](MInt(10), MInt(10)) //100
_ <- sumAndShow[IO, String]("Hello", "World") //HelloWorld
} yield ExitCode.Success
}

How to connect two Scala Futures

I have two Future functions:
def parseIntFuture(str: String) = Future{scala.util.Try(str.toInt).toOption}
def divideFuture(a: Int, b: Int) = Future{ if (b == 0) None else Some(a / b)}
And now I want connect them and eventually get a Future[Option[Int]] type result which is the second one's return value, but if I do like this:
def stringDivideBy(aStr: String, bStr: String) = {
val x = for {
aNum <- parseIntFuture(aStr)
bNum <- parseIntFuture(bStr)
} yield (aNum, bNum)
x.map(n => {
for{
a <- n._1
b <- n._2
} yield divideFuture(a, b)
})
}
Actually I will get Future[Option[Future[Option[Int]]]] instead of Future[Option[Int]] only. I know it's because I'm passing one Future to the other, but I don't know what is the correct way to connect these two Futures one by one avoiding using Await. I halt explicitly use Await, then what would be the solution?
You don't need monad transformers and other "heavy artillery" for simple stuff like this. The general rule is don't make your code more complex than it absolutely has to be.
(parseIntFuture(foo) zip parseIntFuture(bar))
.flatMap {
case (Some(a), Some(b)) => divideFuture(a, b)
case _ => Future.successful(None)
}
There is this thing called OptionT monad transformer that solves exactly this problem. With OptionT, your code would look somewhat like
import cats.data.OptionT
// ...
val x = (for {
aNum <- OptionT(parseIntFuture(aStr))
bNum <- OptionT(parseIntFuture(bStr))
res <- OptionT(divideFuture(aNum, bNum))
} yield res).value
and return a Future[Option[Int]].
You could avoid monad transformers at the cost of nested for-comprehensions:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
def parseIntFuture(str: String) = Future{scala.util.Try(str.toInt).toOption}
def divideFuture(a: Int, b: Int) = Future{ if (b == 0) None else Some(a / b)}
def stringDivideBy(aStr: String, bStr: String): Future[Option[Int]] = {
for {
aOpt <- parseIntFuture(aStr)
bOpt <- parseIntFuture(bStr)
resOpt <-
(for {
a <- aOpt
b <- bOpt
} yield divideFuture(a, b))
.getOrElse(Future { None })
} yield resOpt
}

How to remove many layers of Future Option Future in the response

How can I "fix" this response, I wanted Future[Option[F4]]
val f4Response: Future[Option[Future[Option[Future[F4]]]]] =
for {
f1Opt <- api.getF1() // Future[Option[F1]]
f2Opt <- if (f1Opt.isDefined) api.getF2(f1Opt.get.id) else Future.successful(None) // getF2 is Future[Option[F3]]
} yield {
for {
f1 <- f1Opt
f2 <- f2Opt
} yield {
for {
f3Opt <- api.getF3(f1.id, f2.id) // Future[Option[F3]]
} yield {
for {
f3 <- f3Opt
} yield {
api.insertF(f1, f2, f3) // Future[Option[F4]]
}
}
}
}
Update
I'm trying to use scalaz but I am getting an error:
val result: Future[Option[f4]] = (
for {
f1 <- OptionT(api.getF1(..))
f2 <- OptionT(api.getF2(..))
f3 <- OptionT(api.getF3(f1.id, f2.id)
} yield api.getF4(f1, f2, f3)
).run
Error is:
[error] found : scala.concurrent.Future[Option[scala.concurrent.Future[F4]]]
[error] required: scala.concurrent.Future[Option[F4]]
Also, I can't access f1.id and f2.id in the line:
f3 <- OptionT(api.getF3(f1.id, f2.id)
That's the perfect fit for cats OptionT monad transformer.
You need some cats imports:
import cats.data.OptionT
import cats.instances.future._
let's say this is your data structure (mocked):
case class F1(id: Int)
case class F2(id: Int)
case class F3(id: Int)
trait F4
object api {
def getF1(): Future[Option[F1]] = ???
def getF2(f1: Int): Future[Option[F2]] = ???
def getF3(f1: Int, f2: Int): Future[Option[F3]] = ???
def insertF(f1: Int, f2: Int, f3: Int): Future[Option[F4]] = ???
}
then you can do:
val resultT: OptionT[Future, F4] = for {
f1 <- OptionT(api.getF1())
f2 <- OptionT(api.getF2(f1.id))
f3 <- OptionT(api.getF3(f1.id, f2.id))
f4 <- OptionT(api.insertF(f1.id, f2.id, f3.id))
} yield f4
val result: Future[Option[F4]] = resultT.value
Alternatively you can directly wrap your methods with OptionT :
type FutOpt[T] = OptionT[Future, T]
def getF1(): FutOpt[F1] = OptionT { ??? }
def getF2(f1: Int): FutOpt[F2] = OptionT { ??? }
def getF3(f1: Int, f2: Int): FutOpt[F3] = OptionT { ??? }
def insertF(f1: Int, f2: Int, f3: Int): FutOpt[F4] = OptionT { ??? }
val resultT: FutOpt[F4] = for {
f1 <- api.getF1()
f2 <- api.getF2(f1.id)
f3 <- api.getF3(f1.id, f2.id)
f4 <- api.insertF(f1.id, f2.id, f3.id)
} yield f4
val result: Future[Option[F4]] = resultT.value
You can also use scalaz OptionT keeping the exact same syntax (except for .value -> .run) just by changing imports.
import scalaz._
import Scalaz._
Having def insertF(f1: Int, f2: Int, f3: Int): Future[F4] instead of Future[Option[F4]] you can rewrite the for-comprehension (using scalaz) as:
val resultT: OptionT[Future, F4] = for {
f1 <- OptionT(api.getF1())
f2 <- OptionT(api.getF2(f1.id))
f3 <- OptionT(api.getF3(f1.id, f2.id))
f4 <- api.insertF(f1.id, f2.id, f3.id).liftM[OptionT]
} yield f4
val result: Future[Option[F4]] = resultT.run
val f4Response: Future[Option[Int]] = api.getF1() flatMap {
case Some(f1) => {
api.getF2(f1).flatMap {
case Some(f2) => {
api.getF3(f1.id, f2.id).flatMap {
case Some(f3) => bar(f1, f2, f3)
}
}
}
}
}
for yield maybe it's unnecessary for this scenario patter match maybe is better, no Option.get directly(it maybe will fail), it's more safe for pattern match.

Converting multiple optional values in Scala

I am writing a function that receives several optional String values and converts each one to either an Int or a Boolean and then passes the converted values to Unit functions for further processing. If any conversion fails, the entire function should fail with an error. If all conversions succeed, the function should process the converted values and return a success.
Here is the function I have written (simplified from the actual):
f(x: Option[String], y: Option[String], z: Option[String]): Result = {
val convertX = x.map(value => Try(value.toInt))
val convertY = y.map(value => Try(value.toBoolean))
val convertZ = z.map(value => Try(value.toBoolean))
val failuresExist =
List(convertX, convertY, convertZ).flatten.exists(_.isFailure)
if (failuresExist) BadRequest("Cannot convert input")
else {
convertX.foreach {
case Success(value) => processX(value)
case _ =>
}
convertY.foreach {
case Success(value) => processY(value)
case _ =>
}
convertZ.foreach {
case Success(value) => processZ(value)
case _ =>
}
Ok()
}
}
Although this solution will probably work, it is very awkward. How can I improve it?
A more imperative style could work, if you don't mind that.
def f(x: Option[String], y: Option[String], z: Option[String]): Result = {
try {
val convertX = x.map(_.toInt)
val convertY = y.map(_.toBoolean)
val convertZ = z.map(_.toBoolean)
convertX.foreach(processX)
convertY.foreach(processY)
convertZ.foreach(processZ)
Ok()
} catch {
case _: IllegalArgumentException | _: NumberFormatException => BadRequest("Cannot convert input")
}
}
If you're using scalaz I would use the Option applicative and ApplicativeBuilder's |#| combinator. If any of the inputs are None, then the result is also None.
import scalaz.std.option.optionInstance
import scalaz.syntax.apply._
val result: Option[String] =
Some(1) |#| Some("a") |#| Some(true) apply {
(int, str, bool) =>
s"int is $int, str is $str, bool is $bool"
}
In pure scala, you could use flatMap on option:
val result: Option[String] =
for {
a <- aOpt
b <- bOpt
c <- cOpt
} yield s"$a $b $c"
I personally prefer the applicative because it makes it clear that the results are independent. for-blocks read to me like "first do this with a, then this with b, then this with c" whereas applicative style is more like "with all of a, b, and c, do ..."
Another option with scalaz is sequence, which inverts a structure like T[A[X]] into A[T[X]] for traversable T and applicative A.
import scalaz.std.option.optionInstance
import scalaz.std.list.listInstance
import scalaz.syntax.traverse._
val list: List[Option[Int]] = List(Option(1), Option(4), Option(5))
val result: Option[List[Int]] = list.sequence
// Some(List(1, 4, 5))
For completence I am adding the a piece of code here that process the values are required. However if this is better than that the original is debatable. If you want to process all the value and gather the results of the transformation scalaz Validator could be a better option.
import scala.util.Try
val x = Some("12")
val y = Some("false")
val z = Some("hello")
def process(v: Boolean) = println(s"got a $v")
def processx(v: Int) = println(s"got a number $v")
// Abstract the conversion to the appropriate mapping
def mapper[A, B](v: Option[String])(mapping: String => A)(func: Try[A] => B) = for {
cx <- v.map(vv => Try(mapping(vv)))
} yield func(cx)
def f(x: Option[String], y: Option[String], z: Option[String]) = {
//partially apply the function here. We will use that method twice.
def cx[B] = mapper[Int, B](x)(_.toInt) _
def cy[B] = mapper[Boolean, B](y)(_.toBoolean) _
def cz[B] = mapper[Boolean, B](z)(_.toBoolean) _
//if one of the values is a failure then return the BadRequest,
// else process each value and return ok
(for {
vx <- cx(_.isFailure)
vy <- cy(_.isFailure)
vz <- cz(_.isFailure)
if vx || vy || vz
} yield {
"BadRequest Cannot convert input"
}) getOrElse {
cx(_.map(processx))
cy(_.map(process))
cz(_.map(process))
"OK"
}
}
f(x,y,z)
In the case a "short circuit" behaviour is required the following code will work.
import scala.util.Try
val x = Some("12")
val y = Some("false")
val z = Some("hello")
def process(v: Boolean) = println(s"got a $v")
def processx(v: Int) = println(s"got a number $v")
def f(x: Option[String], y: Option[String], z: Option[String]) =
(for {
cx <- x.map(v => Try(v.toInt))
cy <- y.map(v => Try(v.toBoolean))
cz <- z.map(v => Try(v.toBoolean))
} yield {
val lst = List(cx, cy, cz)
lst.exists(_.isFailure) match {
case true => "BadRequest Cannot convert input"
case _ =>
cx.map(processx)
cy.map(process)
cz.map(process)
"OK"
}
}) getOrElse "Bad Request: missing values"
f(x,y,z)

Safe partial function

I want to convert a partial function into a "safe" partial function, i.e. PartialFunction[T,R] into a PartialFunction[T,Try[R]], is there any better way than the following implementation?
def safe[T,R](pf:PartialFunction[T,R]):PartialFunction[T,Try[R]]=new PartialFunction[T, Try[R]]{
def isDefinedAt(t:T) = pf.isDefinedAt(t)
def apply(t:T) = Try(pf.apply(t))
}
You can define safe using a for expression:
def safe[T,R](pf:PartialFunction[T,R]) = PartialFunction {
(t:T) => for(a <- Try(pf(t))) yield a
}
Or using an implicit class:
object SafeImplicit {
implicit class Safe[T,R](pf: PartialFunction[T,R]){
def safe(t: =>T) = for(a<-Try(pf(t))) yield a
}
}
import SafeImplicit.Safe
def f: PartialFunction[Int, String] = {case 1 => "one"}
def g: PartialFunction[Int, String] = {case 1 => "a".toInt;"one"}
f.safe(1) // Success(one)
f.safe(2) // Failure(scala.MatchError: 2 ...)
f.safe("a".toInt) // Failure(java.lang.NumberFormatException ...)
g.safe(1) // Failure(java.lang.NumberFormatException ...)