arrow.data.NonEmptyList.kt Maven / Gradle / Ivy
package arrow.data
import arrow.*
import arrow.core.*
import arrow.typeclasses.Applicative
import arrow.typeclasses.foldable
typealias Nel = NonEmptyList
/**
* A List that can not be empty
*/
@higherkind
class NonEmptyList private constructor(
val head: A,
val tail: List,
val all: List) : NonEmptyListKind {
constructor(head: A, tail: List) : this(head, tail, listOf(head) + tail)
private constructor(list: List) : this(list[0], list.drop(1), list)
val size: Int = all.size
fun contains(element: @UnsafeVariance A): Boolean = (head == element) || element in tail
fun containsAll(elements: Collection<@UnsafeVariance A>): Boolean = elements.all(this::contains)
fun isEmpty(): Boolean = false
fun map(f: (A) -> B): NonEmptyList = NonEmptyList(f(head), tail.map(f))
fun flatMap(f: (A) -> NonEmptyListKind): NonEmptyList = f(head).ev() + tail.flatMap { f(it).ev().all }
fun ap(ff: NonEmptyListKind<(A) -> B>): NonEmptyList = ff.ev().flatMap { f -> map(f) }.ev()
operator fun plus(l: NonEmptyList<@UnsafeVariance A>): NonEmptyList = NonEmptyList(all + l.all)
operator fun plus(l: List<@UnsafeVariance A>): NonEmptyList = NonEmptyList(all + l)
operator fun plus(a: @UnsafeVariance A): NonEmptyList = NonEmptyList(all + a)
fun foldLeft(b: B, f: (B, A) -> B): B = this.ev().tail.fold(f(b, this.ev().head), f)
fun foldRight(lb: Eval, f: (A, Eval) -> Eval): Eval = foldable().foldRight(this.ev().all.k(), lb, f)
fun traverse(f: (A) -> HK, GA: Applicative): HK> =
GA.map2Eval(f(this.ev().head), Eval.always {
arrow.typeclasses.traverse().traverse(this.ev().tail.k(), f, GA)
}, {
NonEmptyList(it.a, it.b.ev().list)
}).value()
fun coflatMap(f: (NonEmptyListKind) -> B): NonEmptyList {
val buf = mutableListOf()
tailrec fun consume(list: List): List =
if (list.isEmpty()) {
buf
} else {
val tail = list.subList(1, list.size)
buf += f(NonEmptyList(list[0], tail))
consume(tail)
}
return NonEmptyList(f(this), consume(this.ev().tail))
}
fun extract(): A = this.ev().head
fun iterator(): Iterator = all.iterator()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as NonEmptyList<*>
if (all != other.all) return false
return true
}
fun show(): String = all.joinToString()
override fun hashCode(): Int = all.hashCode()
override fun toString(): String = "NonEmptyList(all=$all)"
companion object {
fun of(head: A, vararg t: A): NonEmptyList = NonEmptyList(head, t.asList())
fun fromList(l: List): Option> = if (l.isEmpty()) None else Some(NonEmptyList(l))
fun fromListUnsafe(l: List): NonEmptyList = NonEmptyList(l)
fun pure(a: A): NonEmptyList = a.nel()
@Suppress("UNCHECKED_CAST")
private tailrec fun go(
buf: ArrayList,
f: (A) -> HK>,
v: NonEmptyList>) {
val head: Either = v.head
when (head) {
is Either.Right -> {
buf += head.b
val x = fromList(v.tail)
when (x) {
is Some>> -> go(buf, f, x.t)
is None -> Unit
}
}
is Either.Left -> go(buf, f, f(head.a).ev() + v.tail)
}
}
fun tailRecM(a: A, f: (A) -> HK>): NonEmptyList {
val buf = ArrayList()
go(buf, f, f(a).ev())
return fromListUnsafe(buf)
}
}
}
fun A.nel(): NonEmptyList = NonEmptyList.of(this)
fun NonEmptyList.combineK(y: NonEmptyListKind): NonEmptyList = this.plus(y.ev())
© 2015 - 2025 Weber Informatics LLC | Privacy Policy