Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add more examples to foldable.md #824

Merged
merged 2 commits into from
Jan 30, 2016
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions docs/src/main/tut/foldable.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ First some standard imports.

```tut:silent
import cats._
import cats.std.all._
import cats.implicits._
```

And examples.
Expand Down Expand Up @@ -57,6 +57,10 @@ Foldable[List].traverse_(List("1", "2"))(parseInt)
Foldable[List].traverse_(List("1", "A"))(parseInt)
Foldable[List].sequence_(List(Option(1), Option(2)))
Foldable[List].sequence_(List(Option(1), None))

val prints: Eval[Unit] = List(Eval.always(println(1)), Eval.always(println(2))).sequence_
prints.value

Foldable[List].dropWhile_(List[Int](2,4,5,6,7))(_ % 2 == 0)
Foldable[List].dropWhile_(List[Int](1,2,4,5,6,7))(_ % 2 == 0)

Expand Down Expand Up @@ -86,5 +90,35 @@ as opposed to
def foldRight[A, B](fa: F[A], z: B)(f: (A, B) => B): B
```

which someone familiar with the `foldRight` from the collections in Scala's standard
library might expect.
which someone familiar with the `foldRight` from the collections in
Scala's standard library might expect. This will prevent operations
which are lazy in their right hand argument to traverse the entire
structure unnecessarily. For example, if you have:

```tut
val allFalse = Stream.continually(false)
```

which is an infinite stream of `false` values, and if you wanted to
reduce this to a single false value using the logical and (`&&`). You
intuitively know that the result of this operation should be
`false`. It is not necessary to consider the entire stream in order to
determine this result, you only need to consider the first
value. Using `foldRight` from the standard library *will* try to
consider the entire stream, and thus will eventually cause a stack
overflow:

```tut
try {
allFalse.foldRight(true)(_ && _)
} catch {
case e:StackOverflowError => println(e)
}
```

With the lazy `foldRight` on `Foldable`, the calculation terminates
after looking at only one value:

```tut
Foldable[Stream].foldRight(allFalse, Eval.now(true))((a,b) => Eval.now(a && b.value)).value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that (a,b) => Eval.now(a && b.value) would need to be something like (a,b) => if (a) b else Eval.now(false) in order to be stack safe if there were say 10k true values prepending the continually false values. So it might be a good idea to avoid calling .value until the very end, since that's what you usually want to do with Eval to achieve stack safety.

Having said that, I just gave it a try and it looks like the Cats foldRight implementation for Stream isn't actually stack safe. I'll create a separate issue for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really mean this as a toy example to demonstrate the laziness. I think that it is clearer to read as is. but if you say please I'll change it :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeah, I see your point. It just seems bad to me to write an implementation that isn't stack-safe when a few lines above calls out that the std lib foldRight would hit a stack overflow. And if this is where people come to learn about foldRight, I'd want them to see examples of how to do it "right". I don't want to be a stick in the mud here though, so maybe I should just let it go :)

```