Functional companion to Kotlin's Standard Library providing type-safe error handling and functional programming constructs for iOS x64 target
—
Arrow Core provides extensive extension functions for Iterable, Sequence, and Map collections, adding functional programming capabilities, error handling patterns, and advanced collection operations.
// Zip 3 iterables
fun <A, B, C, D> Iterable<A>.zip(
b: Iterable<B>,
c: Iterable<C>,
transform: (A, B, C) -> D
): List<D>
// Similar patterns for 4-11 parameters
fun <A, B, C, D, E, F> Iterable<A>.zip(
b: Iterable<B>,
c: Iterable<C>,
d: Iterable<D>,
e: Iterable<E>,
transform: (A, B, C, D, E) -> F
): List<F>
// ... up to 11-parameter zip functions// Error accumulation with custom combine function
fun <Error, A, B> Iterable<A>.mapOrAccumulate(
combine: (Error, Error) -> Error,
transform: RaiseAccumulate<Error>.(A) -> B
): Either<Error, List<B>>
// Error accumulation with NonEmptyList errors
fun <Error, A, B> Iterable<A>.mapOrAccumulate(
transform: RaiseAccumulate<Error>.(A) -> B
): Either<NonEmptyList<Error>, List<B>>// Pad zip - handles different lengths
fun <A, B> Iterable<A>.padZip(other: Iterable<B>): List<Pair<A?, B?>>
fun <A, B> Iterable<A>.leftPadZip(other: Iterable<B>): List<Pair<A?, B>>
fun <A, B> Iterable<A>.rightPadZip(other: Iterable<B>): List<Pair<A, B?>>
// Align with Ior for handling missing values
fun <A, B> Iterable<A>.align(b: Iterable<B>): List<Ior<A, B>>// Safe element access
fun <T> Iterable<T>.firstOrNone(): Option<T>
fun <T> Iterable<T>.lastOrNone(): Option<T>
fun <T> Iterable<T>.singleOrNone(): Option<T>
fun <T> Iterable<T>.elementAtOrNone(index: Int): Option<T>// Split into tail and last element
fun <A> Iterable<A>.split(): Pair<List<A>, A>?
// Get tail (all but first)
fun <A> Iterable<A>.tail(): List<A>
// Interleave two iterables
fun <A> Iterable<A>.interleave(other: Iterable<A>): List<A>
// Unweave - flatten nested structures
fun <A, B> Iterable<A>.unweave(ffa: (A) -> Iterable<B>): List<B>// Separate Either values into left and right lists
fun <A, B> Iterable<Either<A, B>>.separateEither(): Pair<List<A>, List<B>>
// Separate Ior values
fun <A, B> Iterable<Ior<A, B>>.separateIor(): Pair<List<A>, List<B>>
fun <A, B> Iterable<Ior<A, B>>.unalign(): Pair<List<A?>, List<B?>>// Safe reduction with nullable result
fun <A, B> Iterable<A>.reduceOrNull(
initial: (A) -> B,
operation: (acc: B, A) -> B
): B?// Zip 3 sequences
fun <A, B, C, D> Sequence<A>.zip(
b: Sequence<B>,
c: Sequence<C>,
transform: (A, B, C) -> D
): Sequence<D>
// Similar patterns for 4-10 parameters
fun <A, B, C, D, E, F> Sequence<A>.zip(
b: Sequence<B>,
c: Sequence<C>,
d: Sequence<D>,
e: Sequence<E>,
transform: (A, B, C, D, E) -> F
): Sequence<F>
// ... up to 10-parameter zip functions// Align sequences with Ior
fun <A, B> Sequence<A>.align(other: Sequence<B>): Sequence<Ior<A, B>>
// Pad zip operations
fun <A, B> Sequence<A>.padZip(other: Sequence<B>): Sequence<Pair<A?, B?>>
fun <A, B> Sequence<A>.leftPadZip(other: Sequence<B>): Sequence<Pair<A?, B>>
fun <A, B> Sequence<A>.rightPadZip(other: Sequence<B>): Sequence<Pair<A, B?>>// Interleave sequences
fun <A> Sequence<A>.interleave(other: Sequence<A>): Sequence<A>
// Split sequence
fun <A> Sequence<A>.split(): Pair<Sequence<A>, A>?
// Get tail
fun <A> Sequence<A>.tail(): Sequence<A>
// Unweave nested sequences
fun <A, B> Sequence<A>.unweave(ffa: (A) -> Sequence<B>): Sequence<B>// Generate multiple sequences
fun <A> Sequence<A>.many(): Sequence<Sequence<A>>
// Single-element sequence
fun <A> Sequence<A>.once(): Sequence<A>
// Align with combining function
fun <A> Sequence<A>.salign(other: Sequence<A>, combine: (A, A) -> A): Sequence<A>// Separate Either sequences
fun <A, B> Sequence<Either<A, B>>.separateEither(): Pair<List<A>, List<B>>
// Unalign Ior sequences
fun <A, B> Sequence<Ior<A, B>>.unalign(): Pair<Sequence<A>, Sequence<B>>
// Filter Option sequences
fun <A> Sequence<Option<A>>.filterOption(): Sequence<A>// Zip two maps
fun <K, A, B> Map<K, A>.zip(other: Map<K, B>): Map<K, Pair<A, B>>
// Zip with transform function
fun <K, A, B, C> Map<K, A>.zip(
other: Map<K, B>,
transform: (K, A, B) -> C
): Map<K, C>
// Multi-argument zip (3-11 parameters)
fun <K, A, B, C, D, E> Map<K, A>.zip(
b: Map<K, B>,
c: Map<K, C>,
d: Map<K, D>,
transform: (K, A, B, C, D) -> E
): Map<K, E>
// ... up to 11-parameter zip functions// Error accumulation on map values
fun <K, E, A, B> Map<K, A>.mapValuesOrAccumulate(
combine: (E, E) -> E,
transform: RaiseAccumulate<E>.(Map.Entry<K, A>) -> B
): Either<E, Map<K, B>>
// FlatMap on values
fun <K, A, B> Map<K, A>.flatMapValues(
f: (Map.Entry<K, A>) -> Map<K, B>
): Map<K, B>// Filter Option values
fun <K, A> Map<K, Option<A>>.filterOption(): Map<K, A>
// Filter by instance type
fun <K, R> Map<K, *>.filterIsInstance(): Map<K, R>// Align maps with Ior
fun <K, A, B> Map<K, A>.align(other: Map<K, B>): Map<K, Ior<A, B>>
// Pad zip maps
fun <K, A, B> Map<K, A>.padZip(other: Map<K, B>): Map<K, Pair<A?, B?>>
// Align with combining function
fun <K, A> Map<K, A>.salign(other: Map<K, A>, combine: (A, A) -> A): Map<K, A>// Unzip pairs
fun <K, A, B> Map<K, Pair<A, B>>.unzip(): Pair<Map<K, A>, Map<K, B>>
// Unalign Ior values
fun <K, A, B> Map<K, Ior<A, B>>.unalign(): Pair<Map<K, A>, Map<K, B>>// Safe get with Option
fun <K, V> Map<K, V>.getOrNone(key: K): Option<V>
// Combine maps with combining function
fun <K, A> Map<K, A>.combine(other: Map<K, A>, combine: (A, A) -> A): Map<K, A>import arrow.core.*
// Zip multiple iterables
val names = listOf("Alice", "Bob", "Charlie")
val ages = listOf(25, 30, 35)
val cities = listOf("NYC", "SF", "LA")
val people = names.zip(ages, cities) { name, age, city ->
"Person(name=$name, age=$age, city=$city)"
}
// Result: ["Person(name=Alice, age=25, city=NYC)", ...]import arrow.core.*
import arrow.core.raise.*
data class ValidationError(val field: String, val message: String)
fun Raise<ValidationError>.validateAge(age: Int): Int {
ensure(age >= 0) { ValidationError("age", "Cannot be negative") }
ensure(age <= 150) { ValidationError("age", "Unrealistic age") }
return age
}
val ages = listOf(25, -5, 200, 30)
val validatedAges = ages.mapOrAccumulate { age ->
validateAge(age)
}
when (validatedAges) {
is Either.Right -> println("All ages valid: ${validatedAges.value}")
is Either.Left -> println("Validation errors: ${validatedAges.value}")
}import arrow.core.*
val shortList = listOf("A", "B")
val longList = listOf(1, 2, 3, 4)
// Pad zip handles different lengths
val padded = shortList.padZip(longList)
// Result: [(Some("A"), Some(1)), (Some("B"), Some(2)), (None, Some(3)), (None, Some(4))]
// Align with Ior
val aligned = shortList.align(longList)
// Result: [Both("A", 1), Both("B", 2), Right(3), Right(4)]import arrow.core.*
val inventory = mapOf("apples" to 10, "bananas" to 5, "oranges" to 3)
val prices = mapOf("apples" to 1.50, "bananas" to 0.75, "oranges" to 2.00)
// Zip maps to calculate total values
val values = inventory.zip(prices) { item, quantity, price ->
quantity * price
}
// Result: {"apples" to 15.0, "bananas" to 3.75, "oranges" to 6.0}
// Safe access with Option
val applePrice = prices.getOrNone("apples") // Some(1.50)
val grapePrice = prices.getOrNone("grapes") // Noneimport arrow.core.*
// Interleave sequences
val evens = sequenceOf(2, 4, 6, 8)
val odds = sequenceOf(1, 3, 5, 7, 9)
val interleaved = evens.interleave(odds).take(8)
// Result: [2, 1, 4, 3, 6, 5, 8, 7]
// Filter Option sequences
val maybeNumbers = sequenceOf(1.some(), none(), 3.some(), none(), 5.some())
val numbers = maybeNumbers.filterOption()
// Result: [1, 3, 5]import arrow.core.*
val results = listOf(
"valid".right(),
"error1".left(),
"also valid".right(),
"error2".left()
)
val (errors, successes) = results.separateEither()
// errors: ["error1", "error2"]
// successes: ["valid", "also valid"]Install with Tessl CLI
npx tessl i tessl/maven-io-arrow-kt--arrow-core-iosx64