How to get Left from a method that returns Future? - scala

def myMethod(myType: String) :Future[Future[Either[List[MyError], MyClass]]] {
for {
first <- runWithSeq(firstSource)
}
yield {
runWithSeq(secondSource)
.map {s ->
val mine = MyClass(s.head, lars)
val errors = myType match {
case "all" => Something.someMethod(mine)
}
(s, errors)
}
.map { x =>
x._2.leftMap(xs => {
addInfo(x._1.head, xs.toList)
}).toEither
}
}
}
for {
myStuff <- myMethod("something")
} yield {
myStuff.collect {
case(Left(errors), rowNumber) =>
MyCaseClass(errors, None) //compilation error here
}
}
I get compilation error on MyCaseClass that expected: List[MyError], found: Any
The signature of MyCaseClass is:
case class MyCaseClass(myErrors: List[ValidationError])
How can I fix this such that I can correctly call MyCaseClass inside the yield?

Your code example doesn't make much sense, and doesn't compile, but if runWithSeq() returns a Future then you should be able to eliminate the double Future return type like so.
for {
_ <- runWithSeq(firstSource)
scnd <- runWithSeq(secondSource)
} yield { ...

Your example is pretty hard to paste and fix
Abstact example for this
Class C may be whatever you want
def test(testval: Int)(implicit ec: ExecutionContext): Future[Future[Either[String, Int]]] = {
Future(Future{
if (testval % 2 == 0) Right(testval) else Left("Smth wrong")
})
}
implicit class FutureEitherExt[A, B](ft: Future[Either[A, B]]) {
def EitherMatch[C](f1: A => C, f2: B => C)(implicit ec: ExecutionContext): Future[C] = {
ft.map {
case Left(value) => f1(value)
case Right(value) => f2(value)
}
}
}
val fl: Future[Either[String, Int]] = test(5).flatten
val result: Future[String] = fl.EitherMatch(identity, _.toString)

Related

How should I get B form A => B

I'm new to Scala, and I'm running into this strange situation.
def bar[A, B](implicit foo: A => B): B = {
// do something
foo
}
And then I got error like
require B but found A => B
How should I get B form A => B
Here's the reason why I did this, I have two functions:
def funcA: String = {
def getStrA: String = "A"
// then there's the same operation in both functions
Try{ } match {
case Success(_) => getStrA
case Failure(_) => // exactlly same error handler in both function
}
}
def funcB: Int = {
def doSomething(x: Int): Int = {
// do something
x / 1
}
val x = 1
Try{ } match {
case Success(_) => doSomething(1)
case Failure(_) => // exactlly same error handler in both function
}
}
Here's what I want to achieve
def funcA: String = {
implicit def getStrA: String = "A"
bar
}
def funcB: Int = {
val x = 1
implicit def doSomething(x: Int): Int = {
// do something
x / 1
}
bar
}
def bar[A, B](implicit foo: A => B): B = {
Try{ } match {
case Success(_) => foo
case Failure(_) => // exactlly same error handler in both function
}
}
You have a conversion from A to B. You need to return B. The only way to do this is to pass A into the function. This signature has an implied assumption that you have some valid A value (most likely hardcoded) that you will always use here.
def bar[A, B](implicit foo: A => B): B = {
val a: A = ... // hmm...
foo(a)
}
Considering, that A is parametric, then you are either missing some information, or this A is impossible to create (it cannot be null because not all types can take null as a value), so you might need to throw exception in such case. Probably you are either missing some A provider or you should always fail this operation.
UPDATE:
There is no need for using implicits at all in your code:
def bar[B](f: onSuccess: A => B) =
Try{ some operations } match {
case Success(value) => onSuccess(value)
case Failure(_) => // error handler
}
def funcA = bar(_ => "A")
def funcB = bar(_ => 1)

Within a function passed to a scala macro, I cannot reference a variable in scope

Cannot compile even if a function that handles function arguments is passed to macro.
A sample is shown below.
trait Generated[Z] {
def deserialize[A](t: A): Z
}
def from[A, Z](apl: A => Z): Generated[Z] = macro GeneratorMacro.from[A, Z]
class GeneratorMacro(val c: blackbox.Context) {
import c.universe._
def from[A: c.WeakTypeTag, Z: c.WeakTypeTag](apl: c.Expr[A => Z]): c.Expr[Generated[Z]] = {
reify {
new Generated[Z] {
def deserialize[A](t: A): Z = {
apl.splice.apply(t)
}
}
}
}
}
object Generation {
def apply(input: String): Generated[Int] = {
Generator.from[Option[String], Int] {
case Some(i) => input.toInt + i.toInt // compilation failed
case None => 0
}
}
}
An error occurs at this time.
Error: scalac: Error while emitting Generation.scala
value input
Isn't the class recompiled with the macro expanded?
If recompiled with inline expansion, no compilation error should occur.
object Generation {
def apply(input: String): Generated[Int] = {
new Generated[Int] {
def deserialize(t: String): Int = {
{
case Some(i) => input.toInt + i.toInt // input should be visible
case None => 0
}.apply(t)
}
}
}
}
What is going on and how to avoid it.
This seems to be impossible, AFAICS. The compiler creates an anonymous class for your code, but it will not capture the lexical context of the macro call inside it.
The code looks a bit like this after the lambdalift phase:
def apply(input: String): Generated[Int] = ({
new <$anon: Generated>()
}: Generated);
...
final class $anon extends Object with Generated {
def deserialize(t: Option): Int = {
... // <- your code is here !!
};
}
Of course, the code has no access to the input variable at this place.
This might be a bug in the Scala compiler...
The first error I have is
Warning:scalac: {
final class $anon extends App.this.Generated[Int] {
def <init>() = {
super.<init>();
()
};
def deserialize(t: Option[String]): Int = ((x0$1: Option[String]) => x0$1 match {
case (value: String)Some[String]((i # _)) => scala.Predef.augmentString(input).toInt.+(scala.Predef.augmentString(i).toInt)
case scala.None => 0
}).apply(t)
};
new $anon()
}
Error:(6, 43) object creation impossible. Missing implementation for:
def deserialize[A](t: A): Int // inherited from trait Generated
Generator.from[Option[String], Int] {
Obviously this is because you define
reify {
new Generated[Z] {
def deserialize(t: A): Z = {
...
instead of def deserialize[A](t: A): Z (#OlegPyzhcov pointed this out in the comments).
Regarding your error Error while emitting ... the thing is that
{
case Some(i: String) => input.toInt + i.toInt
case None => 0
}
has type not ... => ... i.e. Function1[..., ...] but actually PartialFunction[..., ...].
Try either
object Generator {
def from[Z](apl: PartialFunction[Any, Z]): Generated[Z] = macro GeneratorMacro.from[Z]
}
class GeneratorMacro(val c: blackbox.Context) {
import c.universe._
def from[Z: c.WeakTypeTag](apl: c.Expr[Any => Z]): c.Expr[Generated[Z]] = {
reify {
new Generated[Z] {
def deserialize[A](t: A): Z = {
apl.splice.apply(t)
}
}
}
}
}
Generator.from[Int]({
case Some(i: String) => input.toInt + i.toInt
case None => 0
})
or
object Generator {
def from[Z](apl: Any => Z): Generated[Z] = macro GeneratorMacro.from[Z]
}
class GeneratorMacro(val c: blackbox.Context) {
import c.universe._
def from[Z: c.WeakTypeTag](apl: c.Expr[Any => Z]): c.Expr[Generated[Z]] = {
reify {
new Generated[Z] {
def deserialize[A](t: A): Z = {
apl.splice.apply(t)
}
}
}
}
}
Generator.from[Int](new (Any => Int) {
override def apply(x: Any): Int = x match {
case Some(i: String) => input.toInt + i.toInt
case None => 0
}
})

How let State works with Kleisli?

I'm having an example for a logger wrapped with State monad:
val logger = Logger(LoggerFactory.getLogger(this.getClass))
def logState[A](s:IO[Unit], a:A): State[List[IO[Unit]], A] = State[List[IO[Unit]], A]{ logs =>
(logs :+ s, a)
}
type Valid[A] = Exception \/ A
def i2f(i:Int): Valid[BigDecimal] = if (i >= 0) BigDecimal(i).right else (new RuntimeException("Input is smaller then 0")).left
def f2s(f: Valid[BigDecimal]): Valid[String] = f match {
case \/-(f1) => f1.toString.right
case -\/(e) => e.left
}
val comp: Int => State[List[IO[Unit]], Valid[String]] = i => for{
f <- logState(IO{ logger.info(s" => i2f($i)")}, i2f(i))
s <- logState(IO{ logger.info(s" => f2s($f)")}, f2s(f))
} yield s
comp(2)(List.empty) match {
case (logs, a) => {
logs.foreach(_.unsafePerformIO())
a match {
case \/-(s) => println(s"Finally we get: ${s}")
case -\/(e) => println(e.getMessage)
}
}
}
Which works well, but I'm not satisfy with as before I adding State monad, the code was much more clear which was:
type Valid[A] = Exception \/ A
def i2f: Kleisli[Valid, Int, BigDecimal] = Kleisli { i =>
if (i >= 0) BigDecimal(i).right else (new RuntimeException("Input is smaller then 0")).left
}
def f2s: Kleisli[Valid, BigDecimal, String] = Kleisli { f =>
f.toString().right
}
def comp: Kleisli[Valid, Int, String] = i2f andThen f2s
comp(2) match {
case \/-(s) => println(s"Finally we get: ${s}")
case -\/(e) => println(e.getMessage)
}
I'm wondering how let State to work with Kleisli? so that all monads will be working together likes one?
And not the logger will works out of i2f and f2s functions, but also are able to work inside?
All right, got some progress, now the code been:
implicit val ec = scala.concurrent.ExecutionContext.global
type Valid[A] = Exception \/ A
type Report = List[IO[Unit]]
type StateResultT[A] = StateT[Future, Report, A]
implicit val StateResultBind: Bind[StateResultT] = new Bind[StateResultT] {
override def bind[A, B](fa: StateResultT[A])(f: A => StateResultT[B]): StateResultT[B] = fa flatMap f
override def map[A, B](fa: StateResultT[A])(f: A => B): StateResultT[B] = fa map f
}
def i2f: Kleisli[StateResultT, Int, Valid[BigDecimal]] = Kleisli{ i =>
StateT { logs =>
Future (
logs :+ IO(logger.debug("i2f")),
if (i >= 0) BigDecimal(i).right else (new RuntimeException("Input is smaller then 0")).left
)
}
}
def f2s: Kleisli[StateResultT, Valid[BigDecimal], (Report, Valid[String])] = Kleisli { s =>
StateT { logs =>
Future (
logs :+ IO(logger.debug("f2s")),
s match{
case \/-(f) => f.toString.right
case -\/(e) => e.left
}
)
}
}
def comp: Kleisli[StateResultT, Int, Valid[String]] = i2f andThen f2s
Await.result(comp(-2)(List.empty), Duration.Inf) match {
case (logs, a) => {
logs.foreach(_.unsafePerformIO())
a match {
case \/-(s) => println(s"Finally we get: ${s}")
case -\/(e) => println(e.getMessage)
}
}
}

How to pass results from one source stream to another

I have a method that processes a Source and returns. I am trying to modify it but can't seem to be able to return the same thing:
Original
def originalMethod[as: AS, mat: MAT, ec: EC](checkType: String)
: Flow[ByteString, MyValidation[MyClass], NotUsed]{
collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
I am modifying by using another source and pass result of that to the original source and yet return the same thing:
def calculate[T: AS: MAT](source: Source[T, NotUsed]): Future[Seq[T]] =
{
source.runWith(Sink.seq)
}
def modifiedMethod[as: AS, mat: MAT, ec: EC](checkType: String, mySource: Source[LoanApplicationRegister, NotUsed])
: Flow[ByteString, MyValidation[MyClass], NotUsed]{
for {
calc <- calculate(mySource)
orig <- collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code, calc)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
yield {
orig
}
}
But I'm getting compilation error Expression of type Future[Nothing] doesn't conform to existing type Flow[ByteString, MyValidation[MyClass]
How can I return Flow[ByteString, MyValidation[MyClass] in my modifiedMethod just like the originalMethod was
for { calc <- calculate(mySource)}
yield {
collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code, calc)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
would give you a Future[Flow[ByteString, MyValidation[MyClass], NotUsed]] instead of Future[Nothing]
but if you want to remove the Future you'd need to Await somewhere for it (either when you call calculate (and then you don't need the for) or after it. Usually, that's not the way to use Futures

How to create a method which invokes another service and return a Future?

I want to define a method, which will return a Future. And in this method, it will call another service which returns also a Future.
We have defined a BusinessResult to represent Success and Fail:
object validation {
trait BusinessResult[+V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T]
def map[T](f: V => T): BusinessResult[T]
}
sealed case class Success[V](t:V) extends BusinessResult[V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T] = {
f(t)
}
def map[T](f: V => T): BusinessResult[T] = {
Success(f(t))
}
}
sealed case class Fail(e:String) extends BusinessResult[Nothing] {
def flatMap[T](f: Nothing => BusinessResult[T]):BusinessResult[T] = this
def map[T](f: Nothing => T): BusinessResult[T] = this
}
}
And define the method:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import validation._
def name: BusinessResult[String] = Success("my name")
def externalService(name:String):Future[String] = future(name)
def myservice:Future[Int] = {
for {
n <- name
res <- externalService(n)
} yield res match {
case "ok" => 1
case _ => 0
}
}
But which is not compilable. The code in myservice can't return a Future[Int] type.
I also tried to wrap the name with Future:
def myservice:Future[Int] = {
for {
nn <- Future.successful(name)
n <- nn
res <- externalService(n)
} yield res match {
case "ok" => 1
case _ => 0
}
}
Which is also not compilable.
I know there must be a lot of issues in this code. How can I adjust them to make it compilable?
If you change the n with some hardcoded string it works, the problem is that in the for comprehension the variable n has type BusinessResult[String], as you probably already know for comprehension desugarize to map, flatMap and filter so the first part n <- name desugarize to a map on name:
val test: BusinessResult[String] = name.map(x => x)
Intellij thinks n is a String but the scala compiler disagree:
type mismatch;
[error] found : validation.BusinessResult[Nothing]
[error] required: scala.concurrent.Future[Int]
[error] n <- name
[error] ^
Easy solution could be to add a getter method to get back the string and do something like Option does:
object validation {
trait BusinessResult[+V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T]
def map[T](f: V => T): BusinessResult[T]
def getVal: V
}
sealed case class Success[V](t:V) extends BusinessResult[V] {
def flatMap[T](f: V => BusinessResult[T]):BusinessResult[T] = {
f(t)
}
def map[T](f: V => T): BusinessResult[T] = {
Success(f(t))
}
def getVal: V = t
}
sealed case class Fail(e:String) extends BusinessResult[Nothing] {
def flatMap[T](f: Nothing => BusinessResult[T]):BusinessResult[T] = this
def map[T](f: Nothing => T): BusinessResult[T] = this
def getVal = throw new Exception("some message")
}
}
def myservice: Future[Int] = {
val value = name.getVal
for {
res <- externalService(value)
} yield res match {
case "ok" => 1
case _ => 0
}
}
Note that you can't extract the name in the for comprehension since map on String return Chars