or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collection-extensions.mdcore-data-types.mdeffect-system.mdindex.mdraise-dsl.mdtuple-types.md

collection-extensions.mddocs/

0

# Collection Extensions

1

2

Arrow Core provides functional programming extensions for Kotlin collections, focusing on zip operations, alignment operations, error handling, and utility functions.

3

4

## Capabilities

5

6

### Zip Operations

7

8

Enhanced zip operations that support multiple collections and custom transformations.

9

10

```kotlin { .api }

11

/**

12

* Zip with 3 collections using a transform function

13

*/

14

inline fun <B, C, D, E> Iterable<B>.zip(

15

c: Iterable<C>,

16

d: Iterable<D>,

17

transform: (B, C, D) -> E

18

): List<E>

19

20

/**

21

* Zip with 4 collections using a transform function

22

*/

23

inline fun <B, C, D, E, F> Iterable<B>.zip(

24

c: Iterable<C>,

25

d: Iterable<D>,

26

e: Iterable<E>,

27

transform: (B, C, D, E) -> F

28

): List<F>

29

30

/**

31

* Zip operations available up to 10 collections

32

*/

33

```

34

35

**Usage Examples:**

36

37

```kotlin

38

import arrow.core.*

39

40

// Zip three collections

41

val numbers = listOf(1, 2, 3)

42

val letters = listOf("a", "b", "c")

43

val symbols = listOf("!", "?", ".")

44

val combined = numbers.zip(letters, symbols) { num, letter, symbol ->

45

"$num$letter$symbol"

46

}

47

// ["1a!", "2b?", "3c."]

48

49

// Zip four collections

50

val list1 = listOf(1, 2)

51

val list2 = listOf("a", "b")

52

val list3 = listOf(true, false)

53

val list4 = listOf(10.0, 20.0)

54

val result = list1.zip(list2, list3, list4) { num, str, bool, dbl ->

55

Triple(num + str, bool, dbl)

56

}

57

```

58

59

### Map with Error Accumulation

60

61

Transform collections while accumulating errors instead of short-circuiting on the first error.

62

63

```kotlin { .api }

64

/**

65

* Map over collection with error accumulation using custom error combination

66

*/

67

inline fun <Error, A, B> Iterable<A>.mapOrAccumulate(

68

combine: (Error, Error) -> Error,

69

transform: RaiseAccumulate<Error>.(A) -> B

70

): Either<Error, List<B>>

71

72

/**

73

* Map over collection with error accumulation using NonEmptyList

74

*/

75

inline fun <Error, A, B> Iterable<A>.mapOrAccumulate(

76

transform: RaiseAccumulate<Error>.(A) -> B

77

): Either<NonEmptyList<Error>, List<B>>

78

79

/**

80

* Flatten collection of Either values with error accumulation

81

*/

82

inline fun <Error, A> Iterable<Either<Error, A>>.flattenOrAccumulate(

83

combine: (Error, Error) -> Error

84

): Either<Error, List<A>>

85

86

/**

87

* Flatten collection of Either values to NonEmptyList of errors

88

*/

89

fun <Error, A> Iterable<Either<Error, A>>.flattenOrAccumulate(): Either<NonEmptyList<Error>, List<A>>

90

```

91

92

**Usage Examples:**

93

94

```kotlin

95

import arrow.core.*

96

import arrow.core.raise.*

97

98

// Map with error accumulation

99

val inputs = listOf("1", "2", "invalid1", "4", "invalid2")

100

val results = inputs.mapOrAccumulate { str ->

101

str.toIntOrNull() ?: raise("Invalid number: $str")

102

}

103

// Left(NonEmptyList("Invalid number: invalid1", "Invalid number: invalid2"))

104

105

// Custom error combination

106

val customResults = inputs.mapOrAccumulate(

107

combine = { e1, e2 -> "$e1; $e2" }

108

) { str ->

109

str.toIntOrNull() ?: raise("Invalid: $str")

110

}

111

// Left("Invalid: invalid1; Invalid: invalid2")

112

113

// Flatten Either collection

114

val eithers = listOf(1.right(), "error1".left(), 3.right(), "error2".left())

115

val flattened = eithers.flattenOrAccumulate()

116

// Left(NonEmptyList("error1", "error2"))

117

```

118

119

### Alignment Operations

120

121

Combine collections that may have different lengths, handling missing elements gracefully.

122

123

```kotlin { .api }

124

/**

125

* Align two collections using Ior to represent presence

126

*/

127

fun <A, B> Iterable<A>.align(b: Iterable<B>): List<Ior<A, B>>

128

129

/**

130

* Align and transform two collections

131

*/

132

inline fun <A, B, C> Iterable<A>.align(

133

b: Iterable<B>,

134

fa: (Ior<A, B>) -> C

135

): List<C>

136

137

/**

138

* Pad zip - zip with null padding for missing elements

139

*/

140

fun <A, B> Iterable<A>.padZip(other: Iterable<B>): List<Pair<A?, B?>>

141

142

/**

143

* Pad zip with transformation

144

*/

145

inline fun <A, B, C> Iterable<A>.padZip(

146

other: Iterable<B>,

147

fa: (A?, B?) -> C

148

): List<C>

149

150

/**

151

* Left pad zip - keep all elements from right collection

152

*/

153

fun <A, B> Iterable<A>.leftPadZip(other: Iterable<B>): List<Pair<A?, B>>

154

155

/**

156

* Left pad zip with transformation

157

*/

158

inline fun <A, B, C> Iterable<A>.leftPadZip(

159

other: Iterable<B>,

160

fab: (A?, B) -> C

161

): List<C>

162

163

/**

164

* Right pad zip - keep all elements from left collection

165

*/

166

fun <A, B> Iterable<A>.rightPadZip(other: Iterable<B>): List<Pair<A, B?>>

167

168

/**

169

* Right pad zip with transformation

170

*/

171

inline fun <A, B, C> Iterable<A>.rightPadZip(

172

other: Iterable<B>,

173

fa: (A, B?) -> C

174

): List<C>

175

```

176

177

**Usage Examples:**

178

179

```kotlin

180

import arrow.core.*

181

182

// Align collections of different lengths

183

val left = listOf(1, 2, 3)

184

val right = listOf("a", "b")

185

val aligned = left.align(right)

186

// [Ior.Both(1, "a"), Ior.Both(2, "b"), Ior.Left(3)]

187

188

// Align with transformation

189

val combined = left.align(right) { ior ->

190

ior.fold(

191

{ "Left: $it" },

192

{ "Right: $it" },

193

{ l, r -> "Both: $l, $r" }

194

)

195

}

196

// ["Both: 1, a", "Both: 2, b", "Left: 3"]

197

198

// Pad zip with nulls

199

val padded = listOf(1, 2).padZip(listOf("a"))

200

// [Pair(1, "a"), Pair(2, null)]

201

202

// Left pad zip

203

val leftPadded = listOf(1).leftPadZip(listOf("a", "b"))

204

// [Pair(1, "a"), Pair(null, "b")]

205

206

// Right pad zip

207

val rightPadded = listOf(1, 2).rightPadZip(listOf("a"))

208

// [Pair(1, "a"), Pair(2, null)]

209

```

210

211

### Collection Analysis and Utilities

212

213

Utility functions for collection processing and analysis.

214

215

```kotlin { .api }

216

/**

217

* Split collection into head and tail

218

*/

219

fun <A> Iterable<A>.split(): Pair<List<A>, A>?

220

221

/**

222

* Get tail (all but first element)

223

*/

224

fun <A> Iterable<A>.tail(): List<A>

225

226

/**

227

* Interleave elements with another collection

228

*/

229

fun <A> Iterable<A>.interleave(other: Iterable<A>): List<A>

230

231

/**

232

* Unweave using a function that produces iterables

233

*/

234

fun <A, B> Iterable<A>.unweave(ffa: (A) -> Iterable<B>): List<B>

235

236

/**

237

* Separate Either values into lefts and rights

238

*/

239

fun <A, B> Iterable<Either<A, B>>.separateEither(): Pair<List<A>, List<B>>

240

241

/**

242

* Separate Either values with transformation

243

*/

244

inline fun <T, A, B> Iterable<T>.separateEither(

245

f: (T) -> Either<A, B>

246

): Pair<List<A>, List<B>>

247

248

/**

249

* Separate Ior values into components

250

*/

251

fun <A, B> Iterable<Ior<A, B>>.separateIor(): Pair<List<A>, List<B>>

252

253

/**

254

* Unalign Ior values with nulls for missing sides

255

*/

256

fun <A, B> Iterable<Ior<A, B>>.unalign(): Pair<List<A?>, List<B?>>

257

258

/**

259

* Unalign with transformation to Ior

260

*/

261

inline fun <A, B, C> Iterable<C>.unalign(

262

fa: (C) -> Ior<A, B>

263

): Pair<List<A?>, List<B?>>

264

```

265

266

**Usage Examples:**

267

268

```kotlin

269

import arrow.core.*

270

271

// Split into head and tail

272

val numbers = listOf(1, 2, 3, 4)

273

val split = numbers.split()

274

// Pair([2, 3, 4], 1)

275

276

// Interleave collections

277

val evens = listOf(2, 4, 6)

278

val odds = listOf(1, 3, 5, 7)

279

val interleaved = evens.interleave(odds)

280

// [2, 1, 4, 3, 6, 5, 7]

281

282

// Separate Either values

283

val eithers = listOf(1.left(), 2.right(), 3.left(), 4.right())

284

val (lefts, rights) = eithers.separateEither()

285

// lefts: [1, 3], rights: [2, 4]

286

287

// Separate with transformation

288

val numbers2 = listOf(1, 2, 3, 4, 5, 6)

289

val (evens2, odds2) = numbers2.separateEither { num ->

290

if (num % 2 == 0) num.left() else num.right()

291

}

292

// evens2: [2, 4, 6], odds2: [1, 3, 5]

293

294

// Separate Ior values

295

val iors = listOf(

296

Ior.Both("a", 1),

297

Ior.Left("b"),

298

Ior.Right(2)

299

)

300

val (leftValues, rightValues) = iors.separateIor()

301

// leftValues: ["a", "b"], rightValues: [1, 2]

302

```

303

304

### Safe Element Access

305

306

Safe alternatives to collection access operations that return Option instead of throwing exceptions.

307

308

```kotlin { .api }

309

/**

310

* Get first element safely

311

*/

312

fun <T> Iterable<T>.firstOrNone(): Option<T>

313

314

/**

315

* Get first element matching predicate safely

316

*/

317

inline fun <T> Iterable<T>.firstOrNone(predicate: (T) -> Boolean): Option<T>

318

319

/**

320

* Get single element safely

321

*/

322

fun <T> Iterable<T>.singleOrNone(): Option<T>

323

324

/**

325

* Get single element matching predicate safely

326

*/

327

inline fun <T> Iterable<T>.singleOrNone(predicate: (T) -> Boolean): Option<T>

328

329

/**

330

* Get last element safely

331

*/

332

fun <T> Iterable<T>.lastOrNone(): Option<T>

333

334

/**

335

* Get last element matching predicate safely

336

*/

337

inline fun <T> Iterable<T>.lastOrNone(predicate: (T) -> Boolean): Option<T>

338

339

/**

340

* Get element at index safely

341

*/

342

fun <T> Iterable<T>.elementAtOrNone(index: Int): Option<T>

343

```

344

345

**Usage Examples:**

346

347

```kotlin

348

import arrow.core.*

349

350

// Safe first element access

351

val numbers = listOf(1, 2, 3)

352

val first = numbers.firstOrNone() // Some(1)

353

val empty = emptyList<Int>().firstOrNone() // None

354

355

// Safe element access with predicate

356

val even = numbers.firstOrNone { it % 2 == 0 } // Some(2)

357

val notFound = numbers.firstOrNone { it > 10 } // None

358

359

// Safe single element access

360

val single = listOf(42).singleOrNone() // Some(42)

361

val multiple = listOf(1, 2).singleOrNone() // None

362

363

// Safe element at index

364

val atIndex = numbers.elementAtOrNone(1) // Some(2)

365

val outOfBounds = numbers.elementAtOrNone(10) // None

366

```

367

368

### Reduce Operations

369

370

Enhanced reduce operations with proper handling of empty collections.

371

372

```kotlin { .api }

373

/**

374

* Reduce with initial value function, returns null for empty collections

375

*/

376

inline fun <A, B> Iterable<A>.reduceOrNull(

377

initial: (A) -> B,

378

operation: (acc: B, A) -> B

379

): B?

380

381

/**

382

* Right reduce with proper handling of empty collections

383

*/

384

inline fun <A, B> List<A>.reduceRightNull(

385

initial: (A) -> B,

386

operation: (A, acc: B) -> B

387

): B?

388

```

389

390

### Option and Comparison Utilities

391

392

```kotlin { .api }

393

/**

394

* Filter Option values, keeping only Some values

395

*/

396

fun <T> Iterable<Option<T>>.filterOption(): List<T>

397

398

/**

399

* Alias for filterOption

400

*/

401

fun <T> Iterable<Option<T>>.flattenOption(): List<T>

402

403

/**

404

* Prepend element to iterable

405

*/

406

infix fun <T> T.prependTo(list: Iterable<T>): List<T>

407

408

/**

409

* Compare iterables lexicographically

410

*/

411

operator fun <A : Comparable<A>> Iterable<A>.compareTo(other: Iterable<A>): Int

412

413

/**

414

* Crosswalk operation

415

*/

416

fun <A, B> Iterable<A>.crosswalk(f: (A) -> Iterable<B>): List<List<B>>

417

418

/**

419

* Crosswalk with Map result

420

*/

421

fun <A, K, V> Iterable<A>.crosswalkMap(f: (A) -> Map<K, V>): Map<K, List<V>>

422

423

/**

424

* Crosswalk with nullable result

425

*/

426

fun <A, B> Iterable<A>.crosswalkNull(f: (A) -> B?): List<B>?

427

428

/**

429

* Flatten nested iterables

430

*/

431

fun <A> Iterable<Iterable<A>>.flatten(): List<A>

432

```

433

434

## Sequence Extensions

435

436

Arrow Core also provides similar extensions for Sequence with lazy evaluation.

437

438

### Sequence Zip Operations

439

440

```kotlin { .api }

441

/**

442

* Zip sequences with 3-10 parameters, maintaining lazy evaluation

443

*/

444

fun <B, C, D, E> Sequence<B>.zip(

445

c: Sequence<C>,

446

d: Sequence<D>,

447

map: (B, C, D) -> E

448

): Sequence<E>

449

```

450

451

### Sequence Alignment and Padding

452

453

```kotlin { .api }

454

/**

455

* Align two sequences with Ior

456

*/

457

fun <A, B> Sequence<A>.align(seqB: Sequence<B>): Sequence<Ior<A, B>>

458

459

/**

460

* Pad zip sequences with nulls

461

*/

462

fun <A, B> Sequence<A>.padZip(other: Sequence<B>): Sequence<Pair<A?, B?>>

463

464

/**

465

* Left pad zip sequences

466

*/

467

fun <A, B> Sequence<A>.leftPadZip(other: Sequence<B>): Sequence<Pair<A?, B>>

468

469

/**

470

* Right pad zip sequences

471

*/

472

fun <A, B> Sequence<A>.rightPadZip(other: Sequence<B>): Sequence<Pair<A, B?>>

473

```

474

475

### Sequence Utilities

476

477

```kotlin { .api }

478

/**

479

* Split sequence into head and tail

480

*/

481

fun <A> Sequence<A>.split(): Pair<Sequence<A>, A>?

482

483

/**

484

* Interleave sequences

485

*/

486

fun <A> Sequence<A>.interleave(other: Sequence<A>): Sequence<A>

487

488

/**

489

* Filter Option values in sequence

490

*/

491

fun <A> Sequence<Option<A>>.filterOption(): Sequence<A>

492

493

/**

494

* Separate Either values in sequence

495

*/

496

fun <A, B> Sequence<Either<A, B>>.separateEither(): Pair<List<A>, List<B>>

497

498

/**

499

* Map with error accumulation for sequences

500

*/

501

fun <Error, A, B> Sequence<A>.mapOrAccumulate(

502

combine: (Error, Error) -> Error,

503

transform: RaiseAccumulate<Error>.(A) -> B

504

): Either<Error, List<B>>

505

```

506

507

## Map Extensions

508

509

Enhanced operations for Map collections.

510

511

### Map Zip Operations

512

513

```kotlin { .api }

514

/**

515

* Zip maps by key intersection

516

*/

517

fun <K, A, B> Map<K, A>.zip(other: Map<K, B>): Map<K, Pair<A, B>>

518

519

/**

520

* Zip maps with transformation (up to 10 maps)

521

*/

522

inline fun <Key, A, B, C> Map<Key, A>.zip(

523

other: Map<Key, B>,

524

map: (Key, A, B) -> C

525

): Map<Key, C>

526

```

527

528

### Map Alignment and Padding

529

530

```kotlin { .api }

531

/**

532

* Align maps using Ior

533

*/

534

fun <K, A, B> Map<K, A>.align(b: Map<K, B>): Map<K, Ior<A, B>>

535

536

/**

537

* Pad zip maps

538

*/

539

fun <K, A, B> Map<K, A>.padZip(other: Map<K, B>): Map<K, Pair<A?, B?>>

540

541

/**

542

* Structural align with combination function

543

*/

544

fun <K, A> Map<K, A>.salign(

545

other: Map<K, A>,

546

combine: (A, A) -> A

547

): Map<K, A>

548

```

549

550

### Map Utilities

551

552

```kotlin { .api }

553

/**

554

* FlatMap values keeping only matching keys

555

*/

556

fun <K, A, B> Map<K, A>.flatMapValues(f: (Map.Entry<K, A>) -> Map<K, B>): Map<K, B>

557

558

/**

559

* Map values with error accumulation

560

*/

561

inline fun <K, E, A, B> Map<K, A>.mapValuesOrAccumulate(

562

combine: (E, E) -> E,

563

transform: RaiseAccumulate<E>.(Map.Entry<K, A>) -> B

564

): Either<E, Map<K, B>>

565

566

/**

567

* Safe get operation returning Option

568

*/

569

fun <K, V> Map<K, V>.getOrNone(key: K): Option<V>

570

571

/**

572

* Combine maps with function for conflicting keys

573

*/

574

fun <K, A> Map<K, A>.combine(

575

other: Map<K, A>,

576

combine: (A, A) -> A

577

): Map<K, A>

578

579

/**

580

* Filter Option values in map

581

*/

582

fun <K, A> Map<K, Option<A>>.filterOption(): Map<K, A>

583

584

/**

585

* Unalign map of Ior values

586

*/

587

fun <K, A, B> Map<K, Ior<A, B>>.unalign(): Pair<Map<K, A>, Map<K, B>>

588

589

/**

590

* Unzip map of pairs

591

*/

592

fun <K, A, B> Map<K, Pair<A, B>>.unzip(): Pair<Map<K, A>, Map<K, B>>

593

```

594

595

**Usage Examples:**

596

597

```kotlin

598

import arrow.core.*

599

600

// Map zip by intersection

601

val map1 = mapOf(1 to "a", 2 to "b", 3 to "c")

602

val map2 = mapOf(1 to 10, 2 to 20, 4 to 40)

603

val zipped = map1.zip(map2)

604

// {1=(a, 10), 2=(b, 20)}

605

606

// Map alignment

607

val aligned = map1.align(map2)

608

// {1=Ior.Both(a, 10), 2=Ior.Both(b, 20), 3=Ior.Left(c), 4=Ior.Right(40)}

609

610

// Safe get

611

val value = map1.getOrNone(1) // Some("a")

612

val missing = map1.getOrNone(5) // None

613

614

// Combine maps

615

val combined = map1.combine(map2) { str, num -> "$str$num" }

616

// Only works if both maps have same value types

617

```