Note: Don’t confuse this with the collection aggregate operation fold
.
A Fold
is an optic that can see into a structure and get 0 to N foci.
It is a generalization of an instance of Foldable
.
Creating a Fold
can be done by manually defining foldMap
.
import arrow.core.*
import arrow.optics.*
import arrow.typeclasses.*
import arrow.core.extensions.*
fun <T> nullableFold(): Fold<T?, T> = object : Fold<T?, T> {
override fun <R> foldMap(M: Monoid<R>, s: T?, f: (T) -> R): R =
s?.let(f) ?: M.empty()
}
Or you can get a Fold
from any existing Foldable
.
import arrow.core.extensions.nonemptylist.foldable.*
val nonEmptyIntFold: Fold<NonEmptyListOf<Int>, Int> = Fold.fromFoldable(NonEmptyList.foldable())
Fold
has an API similar to Foldable
, but because it’s defined in terms of foldMap
, there are no associative fold functions available.
nullableFold<Int>().isEmpty(null)
// true
nonEmptyIntFold.combineAll(Int.monoid(), NonEmptyList.of(1, 2, 3))
// 6
nullableFold<Int>().headOption(null)
// Option.None
nonEmptyIntFold.headOption(NonEmptyList.of(1, 2, 3, 4))
// Option.Some(1)
Composing Fold
can be used for accessing foci in nested structures.
val nestedNelFold: Fold<NonEmptyListOf<NonEmptyListOf<Int>>, NonEmptyListOf<Int>> = Fold.fromFoldable(NonEmptyList.foldable())
val nestedNel = NonEmptyList.of(1, 2, 3, 4).map {
NonEmptyList.of(it, it)
}
(nestedNelFold compose nonEmptyIntFold).getAll(nestedNel)
// [1, 1, 2, 2, 3, 3, 4, 4]
Fold
can be composed with all optics except Setter
, and results in the following optics.
Iso | Lens | Prism | Optional | Getter | Setter | Fold | Traversal | |
---|---|---|---|---|---|---|---|---|
Fold | Fold | Fold | Fold | Fold | Fold | X | Fold | Fold |
Do you like Arrow?
✖