I have the following for-comprehension which I de-sugared using command scala -Xprint:parser ForComprehensionDemo.scala. When I copy the de-sugared method and call it, it produces different result than the for-comprehension. Any idea why?
For comprehension:
object ForComprehensionDemo {
def main(args: Array[String]): Unit = {
forWithIf(true)
}
def forWithIf(condition: Boolean) = {
val x = for {
a <- name(0)
b <- if (condition) {
name(1)
name(2)
} else {
name(100)
}
c <- name(2)
} yield {
a + b + c
}
println(x)
}
def name(x: Int): Option[String] = {
println("called for :" + x)
x match {
case 0 => Some(" aa ")
case 1 => Some(" bb ")
case 2 => Some(" cc ")
case _ => Some(" not identified ")
}
}
}
Produces result:
called for :0
called for :1
called for :2
called for :2
Some( aa cc cc )
De-sugared code
def forWithIf(condition: Boolean) = {
val x = name(0).flatMap(((a) => if (condition)
{
name(1);
name(2)
}
else
name(100).flatMap(((b) => name(2).map(((c) => a.$plus(b).$plus(c)))))));
println(x)
};
Produces result:
called for :0
called for :1
called for :2
Some( cc )
Just a bug in the pretty printer. It's missing parens around the if-else.
In general, scala 2 doesn't represent parens very faithfully, but scala 3 is much better.
package desugar {
object ForComprehensionDemo extends scala.AnyRef {
def main(args: Array[String]): Unit = forWithIf(true);
def forWithIf(condition: Boolean) = {
val x = name(0).flatMap(((a) => (if (condition)
{
name(1);
name(2)
}
else
name(100)).flatMap(((b) => name(2).map(((c) => a.$plus(b).$plus(c)))))));
println(x)
};
def name(x: Int): Option[String] = {
println("called for :".$plus(x));
x match {
case 0 => Some(" aa ")
case 1 => Some(" bb ")
case 2 => Some(" cc ")
case _ => Some(" not identified ")
}
}
}
}
I was curious to see what Scala 3 says. -Xprint:all says after typer:
sugar.ForComprehensionDemo.name(0).flatMap[String](
{
def $anonfun(a: String): Option[String] =
(if condition then
{
sugar.ForComprehensionDemo.name(1)
sugar.ForComprehensionDemo.name(2)
}
else
{
sugar.ForComprehensionDemo.name(100)
}
).flatMap[String](
{
def $anonfun(b: String): Option[String] =
sugar.ForComprehensionDemo.name(2).map[String](
{
def $anonfun(c: String): String =
{
a.+(b).+(c)
}
closure($anonfun)
}
)
closure($anonfun)
}
)
closure($anonfun)
}
)
That's more inscrutible with the closures, but it has parens. Printing after parser isn't useful.
Just for comparison here is IntelliJ Desugar Scala code... output (with FQNs manually abbreviated)
def forWithIf(condition: Boolean) = {
val x = name(0)
.flatMap(((a) =>
(if (condition) {
name(1);
name(2)
} else {
name(100)
})
.flatMap(((b) =>
name(2)
.map(((c) => a.$plus(b).$plus(c)))))
));
println(x)
};
confirming som-snytt's answer.
Related
object test {
def multBylarge(input: Array[Int]): Int = {
var result=0
var lst: List[Int]=List()
if(input.length == 0) result+=1
else
for(elements <- input) {
lst = lst :+ elements
}
var newlst = lst.sortWith(_ > _)
result += newlst(0) * newlst(1)
result
}
def check2(input: Array[_]) = input.foreach {
case _:Int => multBylarge(_)
case _:Double => "this is a double array"
case _:Float => "this is a float array"
case _=> "this is not a value"
}
def main(args: Array[String]): Unit = {
println(check2(Array(1,3,5,1,3,4)))
}
}
this is my code, I just have no idea. It will be appreciated if anyone can help me with it. And I am not familiar with scala code, so if there has any other problem, please let me know.
Scaladoc is your friend. foreach has return type of scala.Unit (see also) which has only one value - ():
def foreach[U](f: (T) => U): Unit
Apply f to each element for its side effects.
So actual signature of your method is def check2(input: Array[_]): Unit
You can do the following:
Update check2 match on input rather then foreach (since multBylarge requires a array input anyway, foreach wouldn't work here since it iterates over every item in the array then tries to apply it to multBylarge)
Wrap result in a Either (You can think if it as Left = Failure and Right = Successful result)
Then match on the result in the main function to pretty print the result/error
object test {
def multBylarge(input: Array[Int]): Int = {
var result=0
var lst: List[Int]=List()
if(input.length == 0) result+=1
else
for(elements <- input) {
lst = lst :+ elements
}
var newlst = lst.sortWith(_ > _)
result += newlst(0) * newlst(1)
result
}
def check2(input: Array[_]): Either[String, Int] = input match {
case ints: Array[Int] => Right(multBylarge(ints))
case _: Array[Double] => Left("this is a double array")
case _: Array[Float] => Left("this is a float array")
case _. => Left("this is not a value")
}
def main(args: Array[String]): Unit = {
check2(Array(1,3,5,1,3,4)) match {
case Right(result) => println(s"Result is $result")
case Left(error) => println(s"Failed with $error")
}
}
}
I'm trying to figure out how to create an Akka Streams source that generates many Seq[Int].
Basically, given an int n I want to generate all of the Seq[Int] of 1 to n
Here's some code that does this:
def combinations(n: Int): Seq[Seq[Int]] = {
def loop(acc: (Seq[Int], Seq[Seq[Int]]),
remaining: Seq[Int]): Seq[Seq[Int]] = {
remaining match {
case s if s.size == 1 => {
val total: Seq[Seq[Int]] = acc._2
val current: Seq[Int] = acc._1
total :+ (current :+ s.head)
}
case _ => {
for {
x <- remaining
comb <- loop((acc._1 :+ x, acc._2), remaining.filter(_ != x))
} yield comb
}
}
}
loop((Seq(), Seq()), (1 to n))
}
This works fine up to 10... then it blows up because it runs out of memory. Since I just want to process each of them and don't need to keep them all in memory, I thought... Akka Streams. But I'm at a loss for how to turn this into a Source that produces each combination so I can process them. Basically there where it's appending to total I would produce another item onto the stream.
Here is a solution that uses the Johnson-Trotter algorithm for permutations. tcopermutations creates a LazyList that can be evaluated as needed. For more permutations, just pass a different value to printNIterations.
The reason for using the Johnson-Trotter algorithm is that it breaks the recursive structure of the permutation finding algorithm. That's important for being able to evaluate successive instances of the permutation and storing them in some kind of lazy list or stream.
object PermutationsTest {
def main(args: Array[String]) = {
printNIterations(50, tcopermutations(5).iterator)
}
def printNIterations(n: Int, it: Iterator[Seq[Int]]): Unit = {
if (n<=0) ()
else {
if (it.hasNext) {
println(it.next())
printNIterations(n - 1, it)
} else ()
}
}
def naivepermutations(n: Int): Seq[Seq[Int]] = {
def loop(acc: Seq[Int], remaining: Seq[Int]): Seq[Seq[Int]] = {
remaining match {
case s if s.size == 1 => {
val current: Seq[Int] = acc
Seq((current :+ s.head))
}
case _ => {
for {
x <- remaining
comb <- loop(acc :+ x, remaining.filter(_ != x))
} yield comb
}
}
}
loop(Seq(), (1 to n))
}
def tcopermutations(n: Int): LazyList[Seq[Int]] = {
val start = (1 to n).map(Element(_, Left))
def loop(v: Seq[Element]): LazyList[Seq[Element]] = {
johnsonTrotter(v) match {
case Some(s) => v #:: loop(s)
case None => LazyList(v)
}
}
loop(start).map(_.map(_.i))
}
def checkIfMobile(seq: Seq[Element], i: Int): Boolean = {
val e = seq(i)
def getAdjacent(s: Seq[Element], d: Direction, j: Int): Int = {
val adjacentIndex = d match {
case Left => j - 1
case Right => j + 1
}
s(adjacentIndex).i
}
if (e.direction == Left && i == 0) false
else if (e.direction == Right && i == seq.size - 1) false
else if (getAdjacent(seq, e.direction, i) < e.i) true
else false
}
def findLargestMobile(seq: Seq[Element]): Option[Int] = {
val mobiles = (0 until seq.size).filter{j => checkIfMobile(seq, j)}
if (mobiles.isEmpty) None
else {
val folded = mobiles.map(x=>(x,seq(x).i)).foldLeft(None: Option[(Int, Int)]){ case (acc, elem) =>
acc match {
case None => Some(elem)
case Some((i, value)) => if (value > elem._2) Some((i, value)) else Some(elem)
}
}
folded.map(_._1)
}
}
def swapLargestMobile(seq: Seq[Element], index: Int): (Seq[Element], Int) = {
val dir = seq(index).direction
val value = seq(index).i
dir match {
case Right =>
val folded = seq.foldLeft((None, Seq()): (Option[Element], Seq[Element])){(acc, elem) =>
val matched = elem.i == value
val newAccOpt = if (matched) Some(elem) else None
val newAccSeq = acc._1 match {
case Some(swapMe) => acc._2 :+ elem :+ swapMe
case None => if (matched) acc._2 else acc._2 :+ elem
}
(newAccOpt, newAccSeq)
}
(folded._2, index + 1)
case Left =>
val folded = seq.foldRight((None, Seq()): (Option[Element], Seq[Element])){(elem, acc) =>
val matched = elem.i == value
val newAccOpt = if (matched) Some(elem) else None
val newAccSeq = acc._1 match {
case Some(swapMe) => swapMe +: elem +: acc._2
case None => if (matched) acc._2 else elem +: acc._2
}
(newAccOpt, newAccSeq)
}
(folded._2, index - 1)
}
}
def revDirLargerThanMobile(seq: Seq[Element], mobile: Int) = {
def reverse(e: Element) = {
e.direction match {
case Left => Element(e.i, Right)
case Right => Element(e.i, Left)
}
}
seq.map{ elem =>
if (elem.i > seq(mobile).i) reverse(elem)
else elem
}
}
def johnsonTrotter(curr: Seq[Element]): Option[Seq[Element]] = {
findLargestMobile(curr).map { m =>
val (swapped, newMobile) = swapLargestMobile(curr, m)
revDirLargerThanMobile(swapped, newMobile)
}
}
trait Direction
case object Left extends Direction
case object Right extends Direction
case class Element(i: Int, direction: Direction)
}
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)
}
}
}
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)
Given the code below that combines sequence of futures and Either, I always get printed "not OK", why is that if the result is a List?
def future1 (i: Int) = Future { if (i==0) Right(1) else Left("error 1") }
def future2 (i: Int) = Future { if (i==0) Right(2) else Left("error 2") }
...
...
val f1 = future1(0)
val f2 = future2(0)
val f3 = Future.sequence(Seq(f1, f2))
f3.map { result =>
result match {
case List(r) => println("ok")
case _ => println("not OK)
}
}
case List(r) would only match a list with one element which would be then bound to r.
To check if the result is an instance of type List use
f3.map { result =>
result match {
case r: List[_] => println("ok")
case _ => println("not OK)
}
}