0
# Collection Extensions
1
2
Arrow Core provides extensive extension functions for Iterable, Sequence, and Map collections, adding functional programming capabilities, error handling patterns, and advanced collection operations.
3
4
## Iterable Extensions
5
6
### Multi-Argument Zip Operations
7
8
```kotlin { .api }
9
// Zip 3 iterables
10
fun <A, B, C, D> Iterable<A>.zip(
11
b: Iterable<B>,
12
c: Iterable<C>,
13
transform: (A, B, C) -> D
14
): List<D>
15
16
// Similar patterns for 4-11 parameters
17
fun <A, B, C, D, E, F> Iterable<A>.zip(
18
b: Iterable<B>,
19
c: Iterable<C>,
20
d: Iterable<D>,
21
e: Iterable<E>,
22
transform: (A, B, C, D, E) -> F
23
): List<F>
24
25
// ... up to 11-parameter zip functions
26
```
27
28
### Error Accumulation Operations
29
30
```kotlin { .api }
31
// Error accumulation with custom combine function
32
fun <Error, A, B> Iterable<A>.mapOrAccumulate(
33
combine: (Error, Error) -> Error,
34
transform: RaiseAccumulate<Error>.(A) -> B
35
): Either<Error, List<B>>
36
37
// Error accumulation with NonEmptyList errors
38
fun <Error, A, B> Iterable<A>.mapOrAccumulate(
39
transform: RaiseAccumulate<Error>.(A) -> B
40
): Either<NonEmptyList<Error>, List<B>>
41
```
42
43
### Padding and Alignment Operations
44
45
```kotlin { .api }
46
// Pad zip - handles different lengths
47
fun <A, B> Iterable<A>.padZip(other: Iterable<B>): List<Pair<A?, B?>>
48
fun <A, B> Iterable<A>.leftPadZip(other: Iterable<B>): List<Pair<A?, B>>
49
fun <A, B> Iterable<A>.rightPadZip(other: Iterable<B>): List<Pair<A, B?>>
50
51
// Align with Ior for handling missing values
52
fun <A, B> Iterable<A>.align(b: Iterable<B>): List<Ior<A, B>>
53
```
54
55
### Option-Based Safe Operations
56
57
```kotlin { .api }
58
// Safe element access
59
fun <T> Iterable<T>.firstOrNone(): Option<T>
60
fun <T> Iterable<T>.lastOrNone(): Option<T>
61
fun <T> Iterable<T>.singleOrNone(): Option<T>
62
fun <T> Iterable<T>.elementAtOrNone(index: Int): Option<T>
63
```
64
65
### Collection Manipulation
66
67
```kotlin { .api }
68
// Split into tail and last element
69
fun <A> Iterable<A>.split(): Pair<List<A>, A>?
70
71
// Get tail (all but first)
72
fun <A> Iterable<A>.tail(): List<A>
73
74
// Interleave two iterables
75
fun <A> Iterable<A>.interleave(other: Iterable<A>): List<A>
76
77
// Unweave - flatten nested structures
78
fun <A, B> Iterable<A>.unweave(ffa: (A) -> Iterable<B>): List<B>
79
```
80
81
### Either and Ior Operations
82
83
```kotlin { .api }
84
// Separate Either values into left and right lists
85
fun <A, B> Iterable<Either<A, B>>.separateEither(): Pair<List<A>, List<B>>
86
87
// Separate Ior values
88
fun <A, B> Iterable<Ior<A, B>>.separateIor(): Pair<List<A>, List<B>>
89
fun <A, B> Iterable<Ior<A, B>>.unalign(): Pair<List<A?>, List<B?>>
90
```
91
92
### Reduction Operations
93
94
```kotlin { .api }
95
// Safe reduction with nullable result
96
fun <A, B> Iterable<A>.reduceOrNull(
97
initial: (A) -> B,
98
operation: (acc: B, A) -> B
99
): B?
100
```
101
102
## Sequence Extensions
103
104
### Multi-Argument Zip Operations
105
106
```kotlin { .api }
107
// Zip 3 sequences
108
fun <A, B, C, D> Sequence<A>.zip(
109
b: Sequence<B>,
110
c: Sequence<C>,
111
transform: (A, B, C) -> D
112
): Sequence<D>
113
114
// Similar patterns for 4-10 parameters
115
fun <A, B, C, D, E, F> Sequence<A>.zip(
116
b: Sequence<B>,
117
c: Sequence<C>,
118
d: Sequence<D>,
119
e: Sequence<E>,
120
transform: (A, B, C, D, E) -> F
121
): Sequence<F>
122
123
// ... up to 10-parameter zip functions
124
```
125
126
### Alignment and Padding
127
128
```kotlin { .api }
129
// Align sequences with Ior
130
fun <A, B> Sequence<A>.align(other: Sequence<B>): Sequence<Ior<A, B>>
131
132
// Pad zip operations
133
fun <A, B> Sequence<A>.padZip(other: Sequence<B>): Sequence<Pair<A?, B?>>
134
fun <A, B> Sequence<A>.leftPadZip(other: Sequence<B>): Sequence<Pair<A?, B>>
135
fun <A, B> Sequence<A>.rightPadZip(other: Sequence<B>): Sequence<Pair<A, B?>>
136
```
137
138
### Sequence Manipulation
139
140
```kotlin { .api }
141
// Interleave sequences
142
fun <A> Sequence<A>.interleave(other: Sequence<A>): Sequence<A>
143
144
// Split sequence
145
fun <A> Sequence<A>.split(): Pair<Sequence<A>, A>?
146
147
// Get tail
148
fun <A> Sequence<A>.tail(): Sequence<A>
149
150
// Unweave nested sequences
151
fun <A, B> Sequence<A>.unweave(ffa: (A) -> Sequence<B>): Sequence<B>
152
```
153
154
### Specialized Operations
155
156
```kotlin { .api }
157
// Generate multiple sequences
158
fun <A> Sequence<A>.many(): Sequence<Sequence<A>>
159
160
// Single-element sequence
161
fun <A> Sequence<A>.once(): Sequence<A>
162
163
// Align with combining function
164
fun <A> Sequence<A>.salign(other: Sequence<A>, combine: (A, A) -> A): Sequence<A>
165
```
166
167
### Either and Option Operations
168
169
```kotlin { .api }
170
// Separate Either sequences
171
fun <A, B> Sequence<Either<A, B>>.separateEither(): Pair<List<A>, List<B>>
172
173
// Unalign Ior sequences
174
fun <A, B> Sequence<Ior<A, B>>.unalign(): Pair<Sequence<A>, Sequence<B>>
175
176
// Filter Option sequences
177
fun <A> Sequence<Option<A>>.filterOption(): Sequence<A>
178
```
179
180
## Map Extensions
181
182
### Multi-Argument Zip Operations
183
184
```kotlin { .api }
185
// Zip two maps
186
fun <K, A, B> Map<K, A>.zip(other: Map<K, B>): Map<K, Pair<A, B>>
187
188
// Zip with transform function
189
fun <K, A, B, C> Map<K, A>.zip(
190
other: Map<K, B>,
191
transform: (K, A, B) -> C
192
): Map<K, C>
193
194
// Multi-argument zip (3-11 parameters)
195
fun <K, A, B, C, D, E> Map<K, A>.zip(
196
b: Map<K, B>,
197
c: Map<K, C>,
198
d: Map<K, D>,
199
transform: (K, A, B, C, D) -> E
200
): Map<K, E>
201
202
// ... up to 11-parameter zip functions
203
```
204
205
### Value Transformation
206
207
```kotlin { .api }
208
// Error accumulation on map values
209
fun <K, E, A, B> Map<K, A>.mapValuesOrAccumulate(
210
combine: (E, E) -> E,
211
transform: RaiseAccumulate<E>.(Map.Entry<K, A>) -> B
212
): Either<E, Map<K, B>>
213
214
// FlatMap on values
215
fun <K, A, B> Map<K, A>.flatMapValues(
216
f: (Map.Entry<K, A>) -> Map<K, B>
217
): Map<K, B>
218
```
219
220
### Filtering Operations
221
222
```kotlin { .api }
223
// Filter Option values
224
fun <K, A> Map<K, Option<A>>.filterOption(): Map<K, A>
225
226
// Filter by instance type
227
fun <K, R> Map<K, *>.filterIsInstance(): Map<K, R>
228
```
229
230
### Alignment and Padding
231
232
```kotlin { .api }
233
// Align maps with Ior
234
fun <K, A, B> Map<K, A>.align(other: Map<K, B>): Map<K, Ior<A, B>>
235
236
// Pad zip maps
237
fun <K, A, B> Map<K, A>.padZip(other: Map<K, B>): Map<K, Pair<A?, B?>>
238
239
// Align with combining function
240
fun <K, A> Map<K, A>.salign(other: Map<K, A>, combine: (A, A) -> A): Map<K, A>
241
```
242
243
### Unzipping Operations
244
245
```kotlin { .api }
246
// Unzip pairs
247
fun <K, A, B> Map<K, Pair<A, B>>.unzip(): Pair<Map<K, A>, Map<K, B>>
248
249
// Unalign Ior values
250
fun <K, A, B> Map<K, Ior<A, B>>.unalign(): Pair<Map<K, A>, Map<K, B>>
251
```
252
253
### Safe Access and Combination
254
255
```kotlin { .api }
256
// Safe get with Option
257
fun <K, V> Map<K, V>.getOrNone(key: K): Option<V>
258
259
// Combine maps with combining function
260
fun <K, A> Map<K, A>.combine(other: Map<K, A>, combine: (A, A) -> A): Map<K, A>
261
```
262
263
## Usage Examples
264
265
### Multi-Argument Zip
266
267
```kotlin
268
import arrow.core.*
269
270
// Zip multiple iterables
271
val names = listOf("Alice", "Bob", "Charlie")
272
val ages = listOf(25, 30, 35)
273
val cities = listOf("NYC", "SF", "LA")
274
275
val people = names.zip(ages, cities) { name, age, city ->
276
"Person(name=$name, age=$age, city=$city)"
277
}
278
// Result: ["Person(name=Alice, age=25, city=NYC)", ...]
279
```
280
281
### Error Accumulation
282
283
```kotlin
284
import arrow.core.*
285
import arrow.core.raise.*
286
287
data class ValidationError(val field: String, val message: String)
288
289
fun Raise<ValidationError>.validateAge(age: Int): Int {
290
ensure(age >= 0) { ValidationError("age", "Cannot be negative") }
291
ensure(age <= 150) { ValidationError("age", "Unrealistic age") }
292
return age
293
}
294
295
val ages = listOf(25, -5, 200, 30)
296
val validatedAges = ages.mapOrAccumulate { age ->
297
validateAge(age)
298
}
299
300
when (validatedAges) {
301
is Either.Right -> println("All ages valid: ${validatedAges.value}")
302
is Either.Left -> println("Validation errors: ${validatedAges.value}")
303
}
304
```
305
306
### Padding and Alignment
307
308
```kotlin
309
import arrow.core.*
310
311
val shortList = listOf("A", "B")
312
val longList = listOf(1, 2, 3, 4)
313
314
// Pad zip handles different lengths
315
val padded = shortList.padZip(longList)
316
// Result: [(Some("A"), Some(1)), (Some("B"), Some(2)), (None, Some(3)), (None, Some(4))]
317
318
// Align with Ior
319
val aligned = shortList.align(longList)
320
// Result: [Both("A", 1), Both("B", 2), Right(3), Right(4)]
321
```
322
323
### Map Operations
324
325
```kotlin
326
import arrow.core.*
327
328
val inventory = mapOf("apples" to 10, "bananas" to 5, "oranges" to 3)
329
val prices = mapOf("apples" to 1.50, "bananas" to 0.75, "oranges" to 2.00)
330
331
// Zip maps to calculate total values
332
val values = inventory.zip(prices) { item, quantity, price ->
333
quantity * price
334
}
335
// Result: {"apples" to 15.0, "bananas" to 3.75, "oranges" to 6.0}
336
337
// Safe access with Option
338
val applePrice = prices.getOrNone("apples") // Some(1.50)
339
val grapePrice = prices.getOrNone("grapes") // None
340
```
341
342
### Sequence Processing
343
344
```kotlin
345
import arrow.core.*
346
347
// Interleave sequences
348
val evens = sequenceOf(2, 4, 6, 8)
349
val odds = sequenceOf(1, 3, 5, 7, 9)
350
351
val interleaved = evens.interleave(odds).take(8)
352
// Result: [2, 1, 4, 3, 6, 5, 8, 7]
353
354
// Filter Option sequences
355
val maybeNumbers = sequenceOf(1.some(), none(), 3.some(), none(), 5.some())
356
val numbers = maybeNumbers.filterOption()
357
// Result: [1, 3, 5]
358
```
359
360
### Either Separation
361
362
```kotlin
363
import arrow.core.*
364
365
val results = listOf(
366
"valid".right(),
367
"error1".left(),
368
"also valid".right(),
369
"error2".left()
370
)
371
372
val (errors, successes) = results.separateEither()
373
// errors: ["error1", "error2"]
374
// successes: ["valid", "also valid"]
375
```