I am learning Funcional Programming in Scala and quite often I need to trace a function evaluation in order to understand better how it works.
For example, having the following function:
def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B =
l match {
case Nil => z
case Cons(x, xs) => f(x, foldRight(xs, z)(f))
}
For the following call:
foldRight(Cons(1, Cons(2, Cons(3, Nil))), 0)(_ + _)
I would like to get printed its evaluation trace, like this:
foldRight(Cons(1, Cons(2, Cons(3, Nil))), 0)(_ + _)
1 + foldRight(Cons(2, Cons(3, Nil)), 0)(_ + _)
1 + (2 + foldRight(Cons(3, Nil), 0)(_ + _))
1 + (2 + (3 + (foldRight(Nil, 0)(_ + _))))
1 + (2 + (3 + (0)))
6
Currently I am doing either manually or injecting ugly print's. How can I achieve that in a convenient elegant way?
I assumed that Cons and :: are the same operations.
If you don't mind getting only the current element and the accumulator you can do the following:
def printable(x:Int, y:Int): Int = {
println("Curr: "+x.toString+" Acc:"+ y.toString)
x+y
}
foldRight(List(1, 2, 3, 4), 0)(printable(_,_))
//> Curr: 4 Acc:0
//| Curr: 3 Acc:4
//| Curr: 2 Acc:7
//| Curr: 1 Acc:9
//| res0: Int = 10
If you want the whole "stacks trace" this will give you the output you asked, although it is far from elegant:
def foldRight[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
var acc = if (l.isEmpty) "" else l.head.toString
def newAcc(acc: String, x: A) = acc + " + (" + x
def rightSide(xs: List[A], z: B, size: Int) = xs.toString + "," + z + ")" * (l.size - size + 1)
def printDebug(left: String, right: String) = println(left + " + foldRight(" + right)
def go(la: List[A], z: B)(f: (A, B) => B): B = la match {
case Nil => z
case x :: xs => {
acc = newAcc(acc, x)
printDebug(acc, rightSide(xs, z, la.size))
f(x, go(xs, z)(f))
}
}
if (l.isEmpty) z
else f(l.head, go(l.tail, z)(f))
}
Note: to get rid of the variable 'acc' you can make a second accumulator in the 'go' function
This one also returns the output you asked for, but doesn't obscure foldRight.
class Trace[A](z: A) {
var list = List[A]()
def store(x: A) = {
list = list :+ x
}
def getTrace(level: Int): String = {
val left = list.take(level).map(x => s"$x + (").mkString
val right = list.drop(level).map(x => s"$x,").mkString
if (right.isEmpty)
s"${left.dropRight(4)}" + ")" * (list.size - 1)
else
s"${left}foldRight(List(${right.init}), $z)" + ")" * (list.size - level - 1)
}
def getFullTrace: String =
{ for (i <- 0 to list.size) yield getTrace(i) }.mkString("\n")
def foldRight(l: List[A], z: A)(f: (A, A) => A): A = l match {
case Nil => z
case x :: xs => store(x); f(x, foldRight(xs, z)(f))
}
}
val start = 0
val t = new Trace[Int](start)
t.foldRight(List(1, 2, 3, 4), start)(_ + _)
t.getFullTrace
Related
case class value(x1:Long, x2: Double, ..., xk: Long, ... ,xn:Int) {
def add(rValue: Value): Value = {
Value(
x1 = x1 + rValue.x1,
...
xk = xk + rValue.xk,
...
xn = xn + rvalu.xn
)
}
}
I want to aggregate case-class('value'), I think this manual implementation is not elegant when n is large (such as n = 500?)
Here is a solution works in Scala3 with build-in api only:
trait Add[N] { def add(x: N, y: N): N }
object Add:
import scala.deriving.Mirror.ProductOf
given Add[Int] = _ + _
given Add[Long] = _ + _
given Add[Float] = _ + _
given Add[Double] = _ + _
given Add[EmptyTuple] = (_, _) => EmptyTuple
given [H, T <: Tuple](using ha: Add[H], ta: Add[T]): Add[H *: T] =
case (hx*:tx, hy*:ty) => ha.add(hx, hy) *: ta.add(tx, ty)
given [P <: Product](using p: ProductOf[P], a: Add[p.MirroredElemTypes]): Add[P] =
(x, y) => p.fromProduct(a.add(Tuple.fromProductTyped(x), Tuple.fromProductTyped(y)))
Then we can define Value class as:
scala> case class Value(x1: Int, x2: Float, x3: Double):
| def add(that: Value): Value = summon[Add[Value]].add(this, that)
|
scala> Value(1, 2, 3).add(Value(3, 4, 5))
val res0: Value = Value(4,6.0,8.0)
Fields in case classes are immutable, return a new instance with all the updated fields.
case class Value(x: Int, y: Int) {
def + (other: Value): Value =
Value(x + other.x, y + other.y)
}
Value(10, 20) + Value(10, 20)
//res0: Value = Value(20,40)
Value(10, 20) + Value(20, 30) + Value(30, 50)
//res1: Value = Value(60,100)
How to emulate following behavior in Scala? i.e. keep folding while some certain conditions on the accumulator are met.
def foldLeftWhile[B](z: B, p: B => Boolean)(op: (B, A) => B): B
For example
scala> val seq = Seq(1, 2, 3, 4)
seq: Seq[Int] = List(1, 2, 3, 4)
scala> seq.foldLeftWhile(0, _ < 3) { (acc, e) => acc + e }
res0: Int = 1
scala> seq.foldLeftWhile(0, _ < 7) { (acc, e) => acc + e }
res1: Int = 6
UPDATES:
Based on #Dima answer, I realized that my intention was a little bit side-effectful. So I made it synchronized with takeWhile, i.e. there would be no advancement if the predicate does not match. And add some more examples to make it clearer. (Note: that will not work with Iterators)
First, note that your example seems wrong. If I understand correctly what you describe, the result should be 1 (the last value on which the predicate _ < 3 was satisfied), not 6
The simplest way to do this is using a return statement, which is very frowned upon in scala, but I thought, I'd mention it for the sake of completeness.
def foldLeftWhile[A, B](seq: Seq[A], z: B, p: B => Boolean)(op: (B, A) => B): B = foldLeft(z) { case (b, a) =>
val result = op(b, a)
if(!p(result)) return b
result
}
Since we want to avoid using return, scanLeft might be a possibility:
seq.toStream.scanLeft(z)(op).takeWhile(p).last
This is a little wasteful, because it accumulates all (matching) results.
You could use iterator instead of toStream to avoid that, but Iterator does not have .last for some reason, so, you'd have to scan through it an extra time explicitly:
seq.iterator.scanLeft(z)(op).takeWhile(p).foldLeft(z) { case (_, b) => b }
It is pretty straightforward to define what you want in scala. You can define an implicit class which will add your function to any TraversableOnce (that includes Seq).
implicit class FoldLeftWhile[A](trav: TraversableOnce[A]) {
def foldLeftWhile[B](init: B)(where: B => Boolean)(op: (B, A) => B): B = {
trav.foldLeft(init)((acc, next) => if (where(acc)) op(acc, next) else acc)
}
}
Seq(1,2,3,4).foldLeftWhile(0)(_ < 3)((acc, e) => acc + e)
Update, since the question was modified:
implicit class FoldLeftWhile[A](trav: TraversableOnce[A]) {
def foldLeftWhile[B](init: B)(where: B => Boolean)(op: (B, A) => B): B = {
trav.foldLeft((init, false))((a,b) => if (a._2) a else {
val r = op(a._1, b)
if (where(r)) (op(a._1, b), false) else (a._1, true)
})._1
}
}
Note that I split your (z: B, p: B => Boolean) into two higher-order functions. That's just a personal scala style preference.
What about this:
def foldLeftWhile[A, B](z: B, xs: Seq[A], p: B => Boolean)(op: (B, A) => B): B = {
def go(acc: B, l: Seq[A]): B = l match {
case h +: t =>
val nacc = op(acc, h)
if(p(nacc)) go(op(nacc, h), t) else nacc
case _ => acc
}
go(z, xs)
}
val a = Seq(1,2,3,4,5,6)
val r = foldLeftWhile(0, a, (x: Int) => x <= 3)(_ + _)
println(s"$r")
Iterate recursively on the collection while the predicate is true, and then return the accumulator.
You cand try it on scalafiddle
After a while I received a lot of good looking answers. So, I combined them to this single post
a very concise solution by #Dima
implicit class FoldLeftWhile[A](seq: Seq[A]) {
def foldLeftWhile[B](z: B)(p: B => Boolean)(op: (B, A) => B): B = {
seq.toStream.scanLeft(z)(op).takeWhile(p).lastOption.getOrElse(z)
}
}
by #ElBaulP (I modified a little bit to match comment by #Dima)
implicit class FoldLeftWhile[A](seq: Seq[A]) {
def foldLeftWhile[B](z: B)(p: B => Boolean)(op: (B, A) => B): B = {
#tailrec
def foldLeftInternal(acc: B, seq: Seq[A]): B = seq match {
case x :: _ =>
val newAcc = op(acc, x)
if (p(newAcc))
foldLeftInternal(newAcc, seq.tail)
else
acc
case _ => acc
}
foldLeftInternal(z, seq)
}
}
Answer by me (involving side effects)
implicit class FoldLeftWhile[A](seq: Seq[A]) {
def foldLeftWhile[B](z: B)(p: B => Boolean)(op: (B, A) => B): B = {
var accumulator = z
seq
.map { e =>
accumulator = op(accumulator, e)
accumulator -> e
}
.takeWhile { case (acc, _) =>
p(acc)
}
.lastOption
.map { case (acc, _) =>
acc
}
.getOrElse(z)
}
}
Fist exemple: predicate for each element
First you can use inner tail recursive function
implicit class TravExt[A](seq: TraversableOnce[A]) {
def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = {
#tailrec
def rec(trav: TraversableOnce[A], z: B): B = trav match {
case head :: tail if f(head) => rec(tail, op(head, z))
case _ => z
}
rec(seq, z)
}
}
Or short version
implicit class TravExt[A](seq: TraversableOnce[A]) {
#tailrec
final def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = seq match {
case head :: tail if f(head) => tail.foldLeftWhile(op(head, z), f)(op)
case _ => z
}
}
Then use it
val a = List(1, 2, 3, 4, 5, 6).foldLeftWhile(0, _ < 3)(_ + _)
//a == 3
Second example: for accumulator value:
implicit class TravExt[A](seq: TraversableOnce[A]) {
def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = {
#tailrec
def rec(trav: TraversableOnce[A], z: B): B = trav match {
case _ if !f(z) => z
case head :: tail => rec(tail, op(head, z))
case _ => z
}
rec(seq, z)
}
}
Or short version
implicit class TravExt[A](seq: TraversableOnce[A]) {
#tailrec
final def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = seq match {
case _ if !f(z) => z
case head :: tail => tail.foldLeftWhile(op(head, z), f)(op)
case _ => z
}
}
Simply use a branch condition on the accumulator:
seq.foldLeft(0, _ < 3) { (acc, e) => if (acc < 3) acc + e else acc}
However you will run every entry of the sequence.
The test("ok") is copied from book "scala with cats" by Noel Welsh and Dave Gurnell pag.254 ("D.4 Safer Folding using Eval
"), the code run fine, it's the trampolined foldRight
import cats.Eval
test("ok") {
val list = (1 to 100000).toList
def foldRightEval[A, B](as: List[A], acc: Eval[B])(fn: (A, Eval[B]) => Eval[B]): Eval[B] =
as match {
case head :: tail =>
Eval.defer(fn(head, foldRightEval(tail, acc)(fn)))
case Nil =>
acc
}
def foldRight[A, B](as: List[A], acc: B)(fn: (A, B) => B): B =
foldRightEval(as, Eval.now(acc)) { (a, b) =>
b.map(fn(a, _))
}.value
val res = foldRight(list, 0L)(_ + _)
assert(res == 5000050000l)
}
The test("ko") returns same values of test("ok") for small list but for long list the value is different. Why?
test("ko") {
val list = (1 to 100000).toList
def foldRightSafer[A, B](as: List[A], acc: B)(fn: (A, B) => B): Eval[B] = as match {
case head :: tail =>
Eval.defer(foldRightSafer(tail, acc)(fn)).map(fn(head, _))
case Nil => Eval.now(acc)
}
val res = foldRightSafer(list, 0)((a, b) => a + b).value
assert(res == 5000050000l)
}
This is #OlegPyzhcov's comment, converted into a community wiki answer
You forgot the L in 0L passed as second argument to foldRightSafer.
Because of that, the inferred generic types of the invocation are
foldRightSafer[Int, Int]((list : List[Int]), (0: Int))((_: Int) + (_: Int))
and so your addition overflows and gives you something smaller than 2000000000 (9 zeroes, Int.MaxValue = 2147483647).
How can a fold be implemented as a for-comprehension in Scala? I see the only way is to use some recursive call? This is a try that is failing, not sure how to do this? What is the best way to implement fold as a for-comprehension
val nums = List(1,2,3)
nums.fold(0)(_+_)
def recFold(acc: Int = 0): Int = {
(for {
a <- nums
b = recFold(a + acc)
} yield b).head
}
recFold(0) //Stack overflow
If you really want to use for, you don't need recursion, but you would need a mutable variable:
val nums = List(1,2,3)
def recFold(zero: Int)(op: (Int, Int) => Int): Int = {
var result: Int = zero
for { a <- nums } result = op(result, a)
result
}
recFold(0)(_ + _) // 6
Which is pretty similar to how foldLeft is actually implemented in TraversableOnce:
def foldLeft[B](z: B)(op: (B, A) => B): B = {
var result = z
this foreach (x => result = op(result, x))
result
}
Fold can be implemented both ways right to left or left to right. No need to use for plus recursion. Recursion is enough.
def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B = {
as match {
case Nil => z
case x :: xs => f(x, foldRight(xs, z)(f))
}
}
#annotation.tailrec
def foldLeft[A, B](as: List[A], z: B)(f: (A, B) => B): B = {
as match {
case Nil => z
case x :: xs => foldLeft(xs, f(x, z))(f)
}
}
How can I generate the factors of an integer in Scala? Here's my take 1:
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = {
if (a > Math.pow(x, 0.5))
return List(x)
x % a match {
case 0 => a :: foo(x / a, a)
case _ => foo(x, a + 1)
}
}
foo(x, 2)
}
factorize(360) // List(2, 2, 2, 3, 3, 5)
Take 2 based on comments from #SpiderPig and #seth-tisue
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = {
(a*a < x, x % a) match {
case (true, 0) => a :: foo(x/a, a)
case (true, _) => foo(x, a+1)
case (false, _) => List(x)
}
}
foo(x, 2)
}
A tail recursive solution:
def factorize(x: Int): List[Int] = {
#tailrec
def foo(x: Int, a: Int = 2, list: List[Int] = Nil): List[Int] = a*a > x match {
case false if x % a == 0 => foo(x / a, a , a :: list)
case false => foo(x , a + 1, list)
case true => x :: list
}
foo(x)
}
Just little improvement of "Take 2" from the question:
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = x % a match {
case _ if a * a > x => List(x)
case 0 => a :: foo(x / a, a)
case _ => foo(x, a + 1)
}
foo(x, 2)
}
Also, the following method may be a little faster (no x % a calculation in the last iteration):
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = if (a * a > x) List(x) else
x % a match {
case 0 => a :: foo(x / a, a)
case _ => foo(x, a + 1)
}
foo(x, 2)
}