
commonMain.arrow.core.Sequence.kt Maven / Gradle / Ivy
@file:OptIn(ExperimentalTypeInference::class)
/**
*
*/
package arrow.core
import arrow.core.Either.Left
import arrow.core.Either.Right
import arrow.core.raise.RaiseAccumulate
import arrow.core.raise.either
import arrow.core.raise.mapOrAccumulate
import kotlin.experimental.ExperimentalTypeInference
/** Adds [kotlin.sequences.zip] support for 3 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
map: (B, C, D) -> E
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
override fun next(): E =
map(iterator1.next(), iterator2.next(), iterator3.next())
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext()
}
}
/** Adds [kotlin.sequences.zip] support for 4 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
e: Sequence,
map: (B, C, D, E) -> F
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
val iterator4 = e.iterator()
override fun next(): F =
map(iterator1.next(), iterator2.next(), iterator3.next(), iterator4.next())
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext() && iterator4.hasNext()
}
}
/** Adds [kotlin.sequences.zip] support for 5 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
e: Sequence,
f: Sequence,
map: (B, C, D, E, F) -> G
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
val iterator4 = e.iterator()
val iterator5 = f.iterator()
override fun next(): G =
map(iterator1.next(), iterator2.next(), iterator3.next(), iterator4.next(), iterator5.next())
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext() && iterator4.hasNext() && iterator5.hasNext()
}
}
/** Adds [kotlin.sequences.zip] support for 6 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
e: Sequence,
f: Sequence,
g: Sequence,
map: (B, C, D, E, F, G) -> H
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
val iterator4 = e.iterator()
val iterator5 = f.iterator()
val iterator6 = g.iterator()
override fun next(): H =
map(iterator1.next(), iterator2.next(), iterator3.next(), iterator4.next(), iterator5.next(), iterator6.next())
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext() && iterator4.hasNext() && iterator5.hasNext() && iterator6.hasNext()
}
}
/** Adds [kotlin.sequences.zip] support for 7 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
e: Sequence,
f: Sequence,
g: Sequence,
h: Sequence,
map: (B, C, D, E, F, G, H) -> I
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
val iterator4 = e.iterator()
val iterator5 = f.iterator()
val iterator6 = g.iterator()
val iterator7 = h.iterator()
override fun next(): I =
map(
iterator1.next(),
iterator2.next(),
iterator3.next(),
iterator4.next(),
iterator5.next(),
iterator6.next(),
iterator7.next()
)
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext() && iterator4.hasNext() && iterator5.hasNext() && iterator6.hasNext() && iterator7.hasNext()
}
}
/** Adds [kotlin.sequences.zip] support for 8 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
e: Sequence,
f: Sequence,
g: Sequence,
h: Sequence,
i: Sequence,
map: (B, C, D, E, F, G, H, I) -> J
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
val iterator4 = e.iterator()
val iterator5 = f.iterator()
val iterator6 = g.iterator()
val iterator7 = h.iterator()
val iterator8 = i.iterator()
override fun next(): J =
map(
iterator1.next(),
iterator2.next(),
iterator3.next(),
iterator4.next(),
iterator5.next(),
iterator6.next(),
iterator7.next(),
iterator8.next()
)
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext() && iterator4.hasNext() && iterator5.hasNext() && iterator6.hasNext() && iterator7.hasNext() && iterator8.hasNext()
}
}
/** Adds [kotlin.sequences.zip] support for 9 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
e: Sequence,
f: Sequence,
g: Sequence,
h: Sequence,
i: Sequence,
j: Sequence,
map: (B, C, D, E, F, G, H, I, J) -> K
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
val iterator4 = e.iterator()
val iterator5 = f.iterator()
val iterator6 = g.iterator()
val iterator7 = h.iterator()
val iterator8 = i.iterator()
val iterator9 = j.iterator()
override fun next(): K =
map(
iterator1.next(),
iterator2.next(),
iterator3.next(),
iterator4.next(),
iterator5.next(),
iterator6.next(),
iterator7.next(),
iterator8.next(),
iterator9.next()
)
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext() && iterator4.hasNext() && iterator5.hasNext() && iterator6.hasNext() && iterator7.hasNext() && iterator8.hasNext() && iterator9.hasNext()
}
}
/** Adds [kotlin.sequences.zip] support for 10 parameters */
public fun Sequence.zip(
c: Sequence,
d: Sequence,
e: Sequence,
f: Sequence,
g: Sequence,
h: Sequence,
i: Sequence,
j: Sequence,
k: Sequence,
map: (B, C, D, E, F, G, H, I, J, K) -> L
): Sequence = Sequence {
object : Iterator {
val iterator1 = [email protected]()
val iterator2 = c.iterator()
val iterator3 = d.iterator()
val iterator4 = e.iterator()
val iterator5 = f.iterator()
val iterator6 = g.iterator()
val iterator7 = h.iterator()
val iterator8 = i.iterator()
val iterator9 = j.iterator()
val iterator10 = k.iterator()
override fun next(): L =
map(
iterator1.next(),
iterator2.next(),
iterator3.next(),
iterator4.next(),
iterator5.next(),
iterator6.next(),
iterator7.next(),
iterator8.next(),
iterator9.next(),
iterator10.next()
)
override fun hasNext(): Boolean =
iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext() && iterator4.hasNext() && iterator5.hasNext() && iterator6.hasNext() && iterator7.hasNext() && iterator8.hasNext() && iterator9.hasNext() && iterator10.hasNext()
}
}
/**
* Combines two [Sequence] by returning [Ior.Both] when both [Sequence] have an item,
* [Ior.Left] when only the first [Sequence] has an item,
* and [Ior.Right] when only the second [Sequence] has an item.
*
* ```kotlin
* import arrow.core.align
* import arrow.core.Ior
* import arrow.core.Ior.Both
* import arrow.core.Ior.Left
* import arrow.core.Ior.Right
* import io.kotest.matchers.shouldBe
*
* fun test() {
* fun Ior.visualise(): String =
* fold({ "$it<" }, { ">$it" }, { a, b -> "$a<>$b" })
*
* sequenceOf("A", "B").align(sequenceOf(1, 2, 3)) { ior ->
* ior.visualise()
* }.toList() shouldBe listOf("A<>1", "B<>2", ">3")
*
* sequenceOf("A", "B", "C").align(sequenceOf(1, 2)) { ior ->
* ior.visualise()
* }.toList() shouldBe listOf("A<>1", "B<>2", "C<")
* }
* ```
*
*
*/
public fun Sequence.align(seqB: Sequence, fa: (Ior) -> C): Sequence =
alignRec(this, seqB, { fa(Ior.Left(it)) }, { fa(Ior.Right(it)) }) { a, b -> fa(Ior.Both(a, b)) }
/**
* Combines two [Sequence] by returning [Ior.Both] when both [Sequence] have an item,
* [Ior.Left] when only the first [Sequence] has an item,
* and [Ior.Right] when only the second [Sequence] has an item.
*
* ```kotlin
* import arrow.core.align
* import arrow.core.Ior.Both
* import arrow.core.Ior.Left
* import arrow.core.Ior.Right
* import io.kotest.matchers.shouldBe
*
* fun test() {
* sequenceOf("A", "B")
* .align(sequenceOf(1, 2, 3)).toList() shouldBe listOf(Both("A", 1), Both("B", 2), Right(3))
*
* sequenceOf("A", "B", "C")
* .align(sequenceOf(1, 2)).toList() shouldBe listOf(Both("A", 1), Both("B", 2), Left("C"))
* }
* ```
*
*
*/
public fun Sequence.align(seqB: Sequence): Sequence> =
alignRec(this, seqB, { Ior.Left(it) }, { Ior.Right(it) }) { a, b -> Ior.Both(a, b) }
private fun alignRec(
ls: Sequence,
rs: Sequence,
left: (X) -> Z,
right: (Y) -> Z,
both: (X, Y) -> Z
): Sequence {
val lsIterator = ls.iterator()
val rsIterator = rs.iterator()
return sequence {
while (lsIterator.hasNext() && rsIterator.hasNext()) {
yield(
both(
lsIterator.next(),
rsIterator.next()
)
)
}
while (lsIterator.hasNext()) yield(left(lsIterator.next()))
while (rsIterator.hasNext()) yield(right(rsIterator.next()))
}
}
@OverloadResolutionByLambdaReturnType
public fun Sequence.crosswalk(f: (A) -> Iterable): List> =
fold(emptyList()) { bs, a ->
f(a).align(bs) { ior ->
ior.fold(
{ listOf(it) },
::identity,
{ l, r -> listOf(l) + r }
)
}
}
public fun Sequence.crosswalkNull(f: (A) -> B?): List? =
fold?>(emptyList()) { bs, a ->
Ior.fromNullables(f(a), bs)?.fold(
{ listOf(it) },
::identity,
{ l, r -> listOf(l) + r }
)
}
public fun Sequence>.flatten(): Sequence =
flatMap(::identity)
/**
* Interleaves the elements of `this` [Sequence] with those of [other] [Sequence].
* Elements of `this` and [other] are taken in turn, and the resulting list is the concatenation of the interleaved elements.
* If one [Sequence] is longer than the other, the remaining elements are appended to the end.
*
* ```kotlin
* import arrow.core.*
* import io.kotest.matchers.shouldBe
*
* fun test() {
* val tags = generateSequence { "#" }.take(5)
* val numbers = generateSequence(0) { it + 1 }.take(3)
* tags.interleave(numbers).toList() shouldBe listOf("#", 0, "#", 1, "#", 2, "#", "#")
* }
* ```
*
*
*/
public fun Sequence.interleave(other: Sequence): Sequence =
sequence {
val lsIterator = [email protected]()
val rsIterator = other.iterator()
while (lsIterator.hasNext() && rsIterator.hasNext()) {
yield(lsIterator.next())
yield(rsIterator.next())
}
yieldAll(lsIterator)
yieldAll(rsIterator)
}
/**
* Returns a [Sequence] containing the result of applying some transformation `(A?, B) -> C`
* on a zip, excluding all cases where the right value is null.
*
* Example:
* ```kotlin
* import arrow.core.leftPadZip
*
* //sampleStart
* val left = sequenceOf(1, 2).leftPadZip(sequenceOf(3)) { l, r -> l?.plus(r) ?: r } // Result: [4]
* val right = sequenceOf(1).leftPadZip(sequenceOf(3, 4)) { l, r -> l?.plus(r) ?: r } // Result: [4, 4]
* val both = sequenceOf(1, 2).leftPadZip(sequenceOf(3, 4)) { l, r -> l?.plus(r) ?: r } // Result: [4, 6]
* //sampleEnd
*
* fun main() {
* println("left = $left")
* println("right = $right")
* println("both = $both")
* }
* ```
*
*/
public fun Sequence.leftPadZip(other: Sequence, fab: (A?, B) -> C): Sequence =
padZip(other) { a: A?, b: B? -> b?.let { fab(a, it) } }.mapNotNull(::identity)
/**
* Returns a [Sequence>] containing the zipped values of the two sequences
* with null for padding on the left.
*
* Example:
* ```kotlin
* import arrow.core.leftPadZip
*
* //sampleStart
* val padRight = sequenceOf(1, 2).leftPadZip(sequenceOf("a")) // Result: [Pair(1, "a")]
* val padLeft = sequenceOf(1).leftPadZip(sequenceOf("a", "b")) // Result: [Pair(1, "a"), Pair(null, "b")]
* val noPadding = sequenceOf(1, 2).leftPadZip(sequenceOf("a", "b")) // Result: [Pair(1, "a"), Pair(2, "b")]
* //sampleEnd
*
* fun main() {
* println("padRight = $padRight")
* println("padLeft = $padLeft")
* println("noPadding = $noPadding")
* }
* ```
*
*/
public fun Sequence.leftPadZip(other: Sequence): Sequence> =
this.leftPadZip(other) { a, b -> a to b }
public fun Sequence.many(): Sequence> =
if (none()) sequenceOf(emptySequence())
else map { generateSequence { it } }
public fun Sequence.once(): Sequence =
firstOrNull()?.let { sequenceOf(it) } ?: emptySequence()
/**
* Returns a [Sequence>] containing the zipped values of the two sequences with null for padding.
*
* Example:
* ```kotlin
* import arrow.core.padZip
*
* //sampleStart
* val padRight = sequenceOf(1, 2).padZip(sequenceOf("a")) // Result: [Pair(1, "a"), Pair(2, null)]
* val padLeft = sequenceOf(1).padZip(sequenceOf("a", "b")) // Result: [Pair(1, "a"), Pair(null, "b")]
* val noPadding = sequenceOf(1, 2).padZip(sequenceOf("a", "b")) // Result: [Pair(1, "a"), Pair(2, "b")]
* //sampleEnd
*
* fun main() {
* println("padRight = $padRight")
* println("padLeft = $padLeft")
* println("noPadding = $noPadding")
* }
* ```
*
*/
public fun Sequence.padZip(other: Sequence): Sequence> =
alignRec(
this,
other,
{ a -> Pair(a, null) },
{ b -> Pair(null, b) },
{ a, b -> Pair(a, b) }
)
/**
* Returns a [Sequence] containing the result of applying some transformation `(A?, B?) -> C` on a zip.
*
* ```kotlin
* import arrow.core.padZip
*
* //sampleStart
* val padZipRight = sequenceOf(1, 2).padZip(sequenceOf(3)) { l, r -> (l?:0) + (r?:0) } // Result: [4, 2]
* val padZipLeft = sequenceOf(1).padZip(sequenceOf(3, 4)) { l, r -> (l?:0) + (r?:0) } // Result: [4, 4]
* val noPadding = sequenceOf(1, 2).padZip(sequenceOf(3, 4)) { l, r -> (l?:0) + (r?:0) } // Result: [4, 6]
* //sampleEnd
*
* fun main() {
* println("padZipRight = $padZipRight")
* println("padZipLeft = $padZipLeft")
* println("noPadding = $noPadding")
* }
* ```
*
*/
public fun Sequence.padZip(other: Sequence, fa: (A?, B?) -> C): Sequence =
alignRec(
this,
other,
{ a -> fa(a, null) },
{ b -> fa(null, b) },
{ a, b -> fa(a, b) }
)
/**
* Returns a [Sequence] containing the result of applying some transformation `(A, B?) -> C`
* on a zip, excluding all cases where the left value is null.
*
* Example:
* ```kotlin
* import arrow.core.rightPadZip
*
* //sampleStart
* val left = sequenceOf(1, 2).rightPadZip(sequenceOf(3)) { l, r -> l + (r?:0) } // Result: [4, 2]
* val right = sequenceOf(1).rightPadZip(sequenceOf(3, 4)) { l, r -> l + (r?:0) } // Result: [4]
* val both = sequenceOf(1, 2).rightPadZip(sequenceOf(3, 4)) { l, r -> l + (r?:0) } // Result: [4, 6]
* //sampleEnd
*
* fun main() {
* println("left = $left")
* println("right = $right")
* println("both = $both")
* }
* ```
*
*/
public fun Sequence.rightPadZip(other: Sequence, fa: (A, B?) -> C): Sequence =
other.leftPadZip(this) { a, b -> fa(b, a) }
/**
* Returns a [Sequence>] containing the zipped values of the two sequences
* with null for padding on the right.
*
* Example:
* ```kotlin
* import arrow.core.rightPadZip
*
* //sampleStart
* val padRight = sequenceOf(1, 2).rightPadZip(sequenceOf("a")) // Result: [Pair(1, "a"), Pair(2, null)]
* val padLeft = sequenceOf(1).rightPadZip(sequenceOf("a", "b")) // Result: [Pair(1, "a")]
* val noPadding = sequenceOf(1, 2).rightPadZip(sequenceOf("a", "b")) // Result: [Pair(1, "a"), Pair(2, "b")]
* //sampleEnd
*
* fun main() {
* println("padRight = $padRight")
* println("padLeft = $padLeft")
* println("noPadding = $noPadding")
* }
* ```
*
*/
public fun Sequence.rightPadZip(other: Sequence): Sequence> =
this.rightPadZip(other) { a, b -> a to b }
/**
* aligns two structures and combine them with the given [combine]
*/
public fun Sequence.salign(
other: Sequence,
combine: (A, A) -> A
): Sequence =
align(other) { it.fold(::identity, ::identity, combine) }
/**
* Separate the inner [Either] values into the [Either.Left] and [Either.Right].
*
* @receiver Iterable of [Either]
* @return a tuple containing Sequence with [Either.Left] and another Sequence with its [Either.Right] values.
*/
public fun Sequence>.separateEither(): Pair, List> =
fold(listOf() to listOf()) { (lefts, rights), either ->
when (either) {
is Left -> lefts + either.value to rights
is Right -> lefts to rights + either.value
}
}
/**
* attempt to split the computation, giving access to the first result.
*
* ```kotlin
* import arrow.core.split
* import io.kotest.matchers.shouldBe
*
* fun test() {
* sequenceOf("A", "B", "C").split()?.let { (tail, head) ->
* head shouldBe "A"
* tail.toList() shouldBe listOf("B", "C")
* }
* emptySequence().split() shouldBe null
* }
* ```
*
*
*/
public fun Sequence.split(): Pair, A>? =
firstOrNull()?.let { first ->
Pair(tail(), first)
}
/** Alias for drop(1) */
public fun Sequence.tail(): Sequence =
drop(1)
public fun Sequence.mapOrAccumulate(
combine: (Error, Error) -> Error,
@BuilderInference transform: RaiseAccumulate.(A) -> B
): Either> = either {
mapOrAccumulate(this@mapOrAccumulate, combine, transform)
}
public fun Sequence.mapOrAccumulate(
@BuilderInference transform: RaiseAccumulate.(A) -> B
): Either, List> = either {
mapOrAccumulate(this@mapOrAccumulate, transform)
}
/**
* splits an union into its component parts.
*
* ```kotlin
* import arrow.core.bothIor
* import arrow.core.leftIor
* import arrow.core.unalign
*
* fun main() {
* //sampleStart
* val result = sequenceOf(("A" to 1).bothIor(), ("B" to 2).bothIor(), "C".leftIor()).unalign()
* //sampleEnd
* println("(${result.first}, ${result.second})")
* }
* ```
*
*/
public fun Sequence>.unalign(): Pair, Sequence> =
fold(emptySequence() to emptySequence()) { (l, r), x ->
x.fold(
{ l + it to r },
{ l to r + it },
{ a, b -> l + a to r + b }
)
}
/**
* after applying the given function, splits the resulting union shaped structure into its components parts
*
* ```kotlin
* import arrow.core.leftIor
* import arrow.core.unalign
*
* fun main() {
* //sampleStart
* val result = sequenceOf(1, 2, 3).unalign { it.leftIor() }
* //sampleEnd
* println("(${result.first.toList()}, ${result.second.toList()})")
* }
* ```
*
*/
public fun Sequence.unalign(fa: (C) -> Ior): Pair, Sequence> =
map(fa).unalign()
/**
* Fair conjunction. Similarly to interleave
*
* ```kotlin
* import arrow.core.unweave
*
* fun main() {
* //sampleStart
* val result = sequenceOf(1,2,3).unweave { i -> sequenceOf("$i, ${i + 1}") }
* //sampleEnd
* println(result.toList())
* }
* ```
*
*/
public fun Sequence.unweave(ffa: (A) -> Sequence): Sequence =
split()?.let { (fa, a) ->
ffa(a).interleave(fa.unweave(ffa))
} ?: emptySequence()
/**
* unzips the structure holding the resulting elements in an `Pair`
*
* ```kotlin
* import arrow.core.unzip
*
* fun main() {
* //sampleStart
* val result = sequenceOf("A" to 1, "B" to 2).unzip()
* //sampleEnd
* println("(${result.first}, ${result.second})")
* }
* ```
*
*/
public fun Sequence>.unzip(): Pair, Sequence> =
fold(emptySequence() to emptySequence()) { (l, r), x ->
l + x.first to r + x.second
}
/**
* after applying the given function unzip the resulting structure into its elements.
*
* ```kotlin
* import arrow.core.unzip
*
* fun main() {
* //sampleStart
* val result =
* sequenceOf("A:1", "B:2", "C:3").unzip { e ->
* e.split(":").let {
* it.first() to it.last()
* }
* }
* //sampleEnd
* println("(${result.first}, ${result.second})")
* }
* ```
*
*/
public fun Sequence.unzip(fc: (C) -> Pair): Pair, Sequence> =
map(fc).unzip()
/**
* Filters out all elements that are [None],
* and unwraps the remaining elements [Some] values.
*
* ```kotlin
* import arrow.core.None
* import arrow.core.Some
* import arrow.core.filterOption
* import io.kotest.matchers.shouldBe
*
* fun test() {
* generateSequence(0) { it + 1 }
* .map { if (it % 2 == 0) Some(it) else None }
* .filterOption()
* .take(5)
* .toList() shouldBe listOf(0, 2, 4, 6, 8)
* }
* ```
*
*
*/
public fun Sequence
© 2015 - 2025 Weber Informatics LLC | Privacy Policy