Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there a fold method for Form in Play 2.0.2?

I'm referring to this:

http://www.playframework.org/documentation/api/2.0.2/scala/index.html#play.api.data.Form

If you search for a method called fold, it shows a method used for handling the form. Is there a reason why this method is called fold? Given that fold already has a meaning for list like objects, it seems that this name could easily cause confusion.

like image 879
Henry Henrinson Avatar asked Jun 29 '12 16:06

Henry Henrinson


1 Answers

The fold on Form is pretty close to the fold on the Either class in the Scala standard library, which is similarly often used to capture the outcome of a process that could either succeed (in which case you have a Right containing the result) or fail (in which case you have a Left containing an error, or maybe leftover input, etc.). So I'll use Either as an example here. Just picture Form[T] as a kind of Either[Form[T], T] if necessary.

Fold on collections

We can (very informally) imagine lists as having lots of different "shapes" (empty lists, lists of length one, length two, etc.), and fold (or foldLeft, in the following example) as a method that collapses any list of the proper type to a single kind of thing, no matter what its shape is:

scala> def catInts(xs: List[Int]): String = xs.foldLeft("")(_ + _.toString)
catInts: (xs: List[Int])String

scala> catInts(List(1, 2, 3, 4))
res0: String = 1234

scala> catInts(Nil)
res1: String = ""

Fold on Either / Form

Similarly we can imagine Either as having two shapes (Right and Left), and its fold as a method that takes an Either of either shape and returns a single kind of thing. Say we have the following method for parsing strings as integers and returning an Either:

def parseInt(s: String): Either[String, Int] =
  try Right(s.toInt) catch {
    case _: NumberFormatException => Left(s)
  }

And the following method that uses fold to collapse the Either:

def toDefault(e: Either[String, Int]): Int = e.fold(_ => 42, identity)

Which we can use like this:

scala> toDefault(parseInt("AAARGH!!"))
res2: Int = 42

scala> toDefault(parseInt("123"))
res3: Int = 123

This is all obviously very impressionistic and hand-wavy, but it might help give a more intuitive sense of how the different fold methods are fundamentally the same kind of thing. You can see the question I linked in a comment above or the Wikipedia entry on catamorphisms for more detail.

like image 183
Travis Brown Avatar answered Sep 21 '22 12:09

Travis Brown