Created
December 10, 2014 15:03
-
-
Save HerringtonDarkholme/4bcdff2f3a978597372f to your computer and use it in GitHub Desktop.
foldLeft and foldRight
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def retry(noTimes: Int)(block: ⇒Future[T]): Future[T] = { | |
| val ns: Iterator[Int] = (1 to noTimes).iterator | |
| val attempts: Iterator[Future[T]] = ns.map(_⇒ ()⇒block) | |
| val failed = Future.failed(new Exception) | |
| attempts.foldLeft(failed) | |
| ((a,block) ⇒ a recoverWith { block() }) | |
| } | |
| retry(3) { block } | |
| = unfolds to | |
| ((failed recoverWith block1) recoverWith block2) recoverWith block3 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def retry(noTimes: Int)(block: ⇒Future[T]): Future[T] = { | |
| val ns: Iterator[Int] = (1 to noTimes).iterator | |
| val attempts: Iterator[Future[T]] = ns.map(_⇒ ()⇒block) | |
| val failed = Future.failed(new Exception) | |
| attempts.foldRight(() ⇒ failed) | |
| ((block, a) ⇒ () ⇒ { block() fallbackTo { a() } }) | |
| } | |
| retry(3) { block } () | |
| = unfolds to | |
| block1 fallbackTo { block2 fallbackTo { block3 fallbackTo { failed }}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Once again, the association of operation is the key factor when choosing one over another between foldLeft and foldRight.
Composing Future[T] requires creating new objects, lazily by the nature of call-by-name parameter.
foldLeftpacks newly created object into the previously created object'srecoverWith. So it needs to evaluate everyFuture'srecoverWIthwhen it fulfills future. Contrarily,foldRightholds tofallbackhastily and, instead,fallbackonly when needed.The laziness of call-by-name parameter is the key here. (Consider, if fallback is evaluated eagerly then no difference shall exists between them). Laziness avoids unnecessary calls. Becuase the
recoverWith's lazy parameter is the right one, it is better modeled as right-associative.(d op (c op (a op b)))It is much like list pushing and concatenation. Concatenating two lists are better modeled as a right-associative operation like
(f2 (f1 (e1 (e2 e3))))because lpush is O(1), while left-associative concatenation(f1 (f2 f3)) ::: (e1 (e2 e3))is much more expensive.