A Fold is an optic that can see into a structure and get 0 to N foci.
It is a generalization of fold, and implements all operators that can be derived from it.
A structure S that has a focus A to which we can apply a function (A) -> R with Monoid<R> to S and get R.
For example, S == List<Int> to which we apply (Int) -> String with Monoid<String> and we get R == String
Creating a Fold can be done by manually defining foldMap.
import arrow.core.*
import arrow.optics.*
import arrow.typeclasses.*
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()
}
Fold has an API similar to kotlin.collections, but because it’s defined in terms of foldMap, there are no associative fold functions available.
nullableFold<Int>().isEmpty(null)
Fold.nonEmptyList<Int>().combineAll(Monoid.int(), nonEmptyListOf(1, 2, 3))
nullableFold<Int>().firstOrNull(null)
Fold.nonEmptyList<Int>().firstOrNull(nonEmptyListOf(1, 2, 3, 4))
Composing Fold can be used for accessing foci in nested structures.
val nestedNelFold: Fold<NonEmptyList<NonEmptyList<Int>>, NonEmptyList<Int>> = Fold.nonEmptyList()
val nestedNel = nonEmptyListOf(1, 2, 3, 4).map {
nonEmptyListOf(it, it)
}
(nestedNelFold compose Fold.nonEmptyList()).getAll(nestedNel)
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?
✖