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.