Non Empty List
NonEmptyList
is a data type used in Λrrow to model ordered lists that guarantee to have at least one value.
Constructing NonEmptyList
A NonEmptyList
guarantees the list always has at least 1 element.
import arrow.core.nonEmptyListOf
import arrow.core.toNonEmptyListOrNull
fun main() {
println(nonEmptyListOf(1, 2, 3, 4, 5))
println(listOf(1, 2, 3).toNonEmptyListOrNull())
println(emptyList<Int>().toNonEmptyListOrNull())
}
NonEmptyList(1, 2, 3, 4, 5)
NonEmptyList(1, 2, 3)
null
head
Unlike List[0]
, NonEmptyList.head
it's a safe operation that guarantees no exception throwing.
import arrow.core.nonEmptyListOf
val value =
//sampleStart
nonEmptyListOf(1, 2, 3, 4, 5).head
//sampleEnd
fun main() {
println(value)
}
foldLeft
When we fold over a NonEmptyList
, we turn a NonEmptyList< A >
into B
by providing a seed value and a function that carries the state on each iteration over the elements of the list. The first argument is a function that addresses the seed value, this can be any object of any type which will then become the resulting typed value. The second argument is a function that takes the current state and element in the iteration and returns the new state after transformations have been applied.
import arrow.core.NonEmptyList
import arrow.core.nonEmptyListOf
//sampleStart
fun sumNel(nel: NonEmptyList<Int>): Int =
nel.foldLeft(0) { acc, n -> acc + n }
val value = sumNel(nonEmptyListOf(1, 1, 1, 1))
//sampleEnd
fun main() {
println("value = $value")
}
map
map
allows us to transform A
into B
in NonEmptyList< A >
import arrow.core.nonEmptyListOf
val value =
//sampleStart
nonEmptyListOf(1, 1, 1, 1).map { it + 1 }
//sampleEnd
fun main() {
println(value)
}
Combining NonEmptyLists
flatMap
flatMap
allows us to compute over the contents of multiple NonEmptyList< * >
values
import arrow.core.NonEmptyList
import arrow.core.nonEmptyListOf
//sampleStart
val nelOne: NonEmptyList<Int> = nonEmptyListOf(1, 2, 3)
val nelTwo: NonEmptyList<Int> = nonEmptyListOf(4, 5)
val value = nelOne.flatMap { one ->
nelTwo.map { two ->
one + two
}
}
//sampleEnd
fun main() {
println("value = $value")
}
zip
Λrrow contains methods that allow you to preserve type information when computing over different NonEmptyList
typed values.
import arrow.core.NonEmptyList
import arrow.core.nonEmptyListOf
import arrow.core.zip
import java.util.UUID
//sampleStart
data class Person(val id: UUID, val name: String, val year: Int)
// Note each NonEmptyList is of a different type
val nelId: NonEmptyList<UUID> = nonEmptyListOf(UUID.randomUUID(), UUID.randomUUID())
val nelName: NonEmptyList<String> = nonEmptyListOf("William Alvin Howard", "Haskell Curry")
val nelYear: NonEmptyList<Int> = nonEmptyListOf(1926, 1900)
val value = nelId.zip(nelName, nelYear) { id, name, year ->
Person(id, name, year)
}
//sampleEnd
fun main() {
println("value = $value")
}
Summary
NonEmptyList
is used to model lists that guarantee at least one elementWe can easily construct values of
NonEmptyList
withnonEmptyListOf
foldLeft
,map
,flatMap
and others are used to compute over the internal contents of aNonEmptyList
value.a.zip(b, c) { ... }
can be used to compute over multipleNonEmptyList
values preserving type information and abstracting over arity withzip
Constructors
Types
Functions
Properties
Extensions
Combine two A values.