简体   繁体   中英

Scala cats trampoline

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 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM