Skip to content

API

Iterum


iterum.iterum

Bases: Iterum[T_co]

Implements an Iterum interface from an iterable object.

Examples:

>>> itr = iterum([1, 2])
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == nil
>>> itr = iterum([1, 2, 3, 4])
>>> assert itr.fold(0, lambda acc, x: acc + x) == 10
>>> x = [0, 1, 2, 3, 4]
>>> y = (
...     iterum(x)
...     .map(lambda x: x**2 + 1)
...     .filter(lambda x: x % 2)
...     .collect()
... )
>>> assert y == [1, 5, 17]
Source code in iterum/_iterum.py
class iterum(Iterum[T_co]):
    """
    Implements an [Iterum][iterum.Iterum] interface from an iterable object.

    Examples:

        >>> itr = iterum([1, 2])
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == nil

        >>> itr = iterum([1, 2, 3, 4])
        >>> assert itr.fold(0, lambda acc, x: acc + x) == 10

        >>> x = [0, 1, 2, 3, 4]
        >>> y = (
        ...     iterum(x)
        ...     .map(lambda x: x**2 + 1)
        ...     .filter(lambda x: x % 2)
        ...     .collect()
        ... )
        >>> assert y == [1, 5, 17]
    """

    __slots__ = ("_iter",)

    def __init__(self, __iterable: Iterable[T_co], /) -> None:
        self._iter = iter(__iterable)

    def next(self) -> Option[T_co]:
        """
        Returns the next value in the iterable if present, otherwise [nil][iterum.nil].

        Examples:

            >>> itr = iterum([1, 2])
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == nil
        """
        return _try_next(self._iter)

next() -> Option[T_co]

Returns the next value in the iterable if present, otherwise nil.

Examples:

>>> itr = iterum([1, 2])
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
def next(self) -> Option[T_co]:
    """
    Returns the next value in the iterable if present, otherwise [nil][iterum.nil].

    Examples:

        >>> itr = iterum([1, 2])
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == nil
    """
    return _try_next(self._iter)

iterum.Iterum

Bases: Iterator[T_co]

Iterator-like abstract base class. To implement this, inherit from Iterum and then define a next method. See iterum for an example.

Source code in iterum/_iterum.py
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
class Iterum(Iterator[T_co]):
    """
    Iterator-like abstract base class. To implement this, inherit from
    [Iterum][iterum.Iterum] and then define a [next][iterum.Iterum.next] method.
    See [iterum][iterum.iterum] for an example.
    """

    __slots__ = ()

    @abstractmethod
    def next(self) -> Option[T_co]:
        """
        Required method.

        Advances the iterum and returns the next value.

        Returns [nil][iterum.nil] when iteration is finished.
        Individual iterum implementations may choose to resume iteration,
        and so calling [next()][iterum.Iterum.next] again may or may not eventually start returning
        [Some(Item)][iterum.Some] again at some point.

        Examples:

            >>> itr = iterum([1, 2, 3])

            A call to next() returns the next value...
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == Some(3)

            ... and then [nil][iterum.nil] once it's over.
            >>> assert itr.next() == nil

            More calls may or may not return [nil][iterum.nil]. Here, they always will.
            >>> assert itr.next() == nil
            >>> assert itr.next() == nil
        """
        return nil

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterum:
            return check_methods(C, "next")
        return NotImplemented

    def __next__(self) -> T_co:
        return self.next().ok_or_else(StopIteration)

    def all(self, f: Callable[[T_co], object], /) -> bool:
        """
        Tests if every element of the iterum matches a predicate.

        [all()][iterum.Iterum.all] takes a closure that returns `True` or `False`.
        It applies this closure to each element of the iterum,
        and if they all return `True`, then so does [all()][iterum.Iterum.all].
        If any of them return `False`, it returns `False`.

        [all()][iterum.Iterum.all] is short-circuiting; in other words, it will
        stop processing as soon as it finds a `False`, given that no matter
        what else happens, the result will also be `False`.

        An empty iterum returns `True`.

        Examples:

            >>> a = [1, 2, 3]
            >>> assert iterum(a).all(lambda x: x > 0)
            >>> assert not iterum(a).all(lambda x: x > 2)

            Stopping at the first `False`:
            >>> itr = iterum([1, 2, 3])
            >>> assert not itr.all(lambda x: x != 2)
            >>> assert itr.next() == Some(3)
        """
        return all(map(f, self))

    def any(self, f: Callable[[T_co], object], /) -> bool:
        """
        Tests if any element of the iterum matches a predicate.

        [any()][iterum.Iterum.any] takes a closure that returns `True` or
        `False`. It applies this closure to each element of the iterum, and if
        any of them return `True`, then so does [any()][iterum.Iterum.any]. If
        they all return `False`, it returns `False`.

        [any()][iterum.Iterum.any] is short-circuiting; in other words, it will
        stop processing as soon as it finds a `True`, given that no matter what
        else happens, the result will also be `True`.

        An empty iterum returns `False`.

        Examples:

            >>> a = [1, 2, 3]
            >>> assert iterum(a).any(lambda x: x > 0)
            >>> assert not iterum(a).any(lambda x: x > 5)


            Stopping at the first `True`:
            >>> itr = iterum([1, 2, 3])
            >>> assert itr.any(lambda x: x != 2)

            itr still has more elements.
            >>> assert itr.next() == Some(2)
        """
        return any(map(f, self))

    def chain(self: Iterum[T_co], other: Iterable[T_co], /) -> Chain[T_co]:
        """
        Takes two iterables and creates a new iterum over both in sequence.

        [chain()][iterum.Iterum.chain] will return a new iterum which will
        first iterate over values from the first iteerable and then over values
        from the second iterable.

        In other words, it links two iterables together, in a chain.

        Examples:

            >>> a1 = [1, 2, 3]
            >>> a2 = [4, 5, 6]
            >>> itr = iterum(a1).chain(a2)
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == Some(3)
            >>> assert itr.next() == Some(4)
            >>> assert itr.next() == Some(5)
            >>> assert itr.next() == Some(6)
            >>> assert itr.next() == nil
        """
        return Chain(self, other)

    @overload
    def cmp(
        self: Iterum[SupportsRichComparison], other: Iterable[object], /
    ) -> Ordering:
        ...

    @overload
    def cmp(
        self: Iterum[object], other: Iterable[SupportsRichComparison], /
    ) -> Ordering:
        ...

    def cmp(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> Ordering:
        """
        Lexicographically compares the elements of this Iterator with those of
        another.

        Examples:

            >>> assert iterum([1]).cmp([1]) == Ordering.Equal
            >>> assert iterum([1, 2]).cmp([1]) == Ordering.Greater
            >>> assert iterum([1]).cmp([1, 2]) == Ordering.Less
        """
        other = iterum(other)
        while True:
            match self.next(), other.next():
                case Some(left), Some(right):
                    if left > right:  # type: ignore | reason: ask for forgiveness not permission
                        return Ordering.Greater
                    if left < right:  # type: ignore | reason: ask for forgiveness not permission
                        return Ordering.Less
                    continue
                case Some(), Nil():
                    return Ordering.Greater

                case Nil(), Some():
                    return Ordering.Less

                case Nil(), Nil():
                    return Ordering.Equal

                case _:
                    raise AssertionError("Unreachable!")

    @overload
    def collect(self: Iterum[T_co], /) -> list[T_co]:
        ...

    @overload
    def collect(self: Iterum[T_co], container: type[list], /) -> list[T_co]:
        ...

    @overload
    def collect(self: Iterum[T_co], container: type[set], /) -> set[T_co]:
        ...

    @overload
    def collect(self: Iterum[T_co], container: type[tuple], /) -> tuple[T_co, ...]:
        ...

    @overload
    def collect(self: Iterum[tuple[U, V]], container: type[dict], /) -> dict[U, V]:
        ...

    @overload
    def collect(self: Iterum[T_co], container: Callable[[Iterable[T_co]], U], /) -> U:
        ...

    def collect(  # type: ignore
        self: Iterum[T_co], container: Callable[[Iterable[T_co]], U] = list, /
    ) -> U:
        """
        Transforms an iterum into a collection.

        [collect()][iterum.Iterum.collect] takes a container which is responsible
        for mapping an iterable into any type. Most commonly this is a collection
        type such as `list` or `set` but could also be a function such as `''.join`.

        Examples:

            >>> doubled = iterum([1, 2, 3]).map(lambda x: x * 2).collect(list)
            >>> assert doubled == [2, 4, 6]

            using `join` to collect an iterable of `str`
            >>> assert iterum("test").map(str.upper).collect("".join) == "TEST"
        """
        return container(self)

    def count(self) -> int:
        """
        Consumes the iterum, counting the number of iterations and returning it.

        This method will call next repeatedly until [nil][iterum.nil] is
        encountered, returning the number of times it saw [Some][iterum.Some].
        Note that next has to be called at least once even if the iterum does
        not have any elements.

        Examples:

            >>> assert iterum([1, 2, 3]).count() == 3
            >>> assert iterum([1, 2, 3, 4, 5]).count() == 5
        """
        last = self.enumerate().last()
        return last.map_or(0, lambda last: last[0] + 1)

    def cycle(self: Iterum[T_co], /) -> Cycle[T_co]:
        """
        Repeats an iterum endlessly.

        Instead of stopping at [nil][iterum.nil], the iterum will instead
        start again, from the beginning. After iterating again, it will start at
        the beginning again. And again. And again. Forever. Note that in case
        the original iterum is empty, the resulting iterum will also be empty.

        Examples:

            >>> a = [1, 2, 3]
            >>> it = iterum(a).cycle()
            >>> assert it.next() == Some(1)
            >>> assert it.next() == Some(2)
            >>> assert it.next() == Some(3)
            >>> assert it.next() == Some(1)
            >>> assert it.next() == Some(2)
            >>> assert it.next() == Some(3)
            >>> assert it.next() == Some(1)
        """
        return Cycle(self)

    def enumerate(self: Iterum[T_co], /) -> Enumerate[T_co]:
        """
        Creates an iterum which gives the current iteration count as well as
        the next value.

        The iterum returned yields pairs (i, val), where i is the current
        index of iteration and val is the value returned by the iterum.

        Examples:

            >>> a = ["a", "b", "c"]
            >>> it = iterum(a).enumerate()
            >>> assert it.next() == Some((0, "a"))
            >>> assert it.next() == Some((1, "b"))
            >>> assert it.next() == Some((2, "c"))
            >>> assert it.next() == nil
        """
        return Enumerate(self)

    @overload
    def eq(self: Iterum[SupportsRichComparison], other: Iterable[object], /) -> bool:
        ...

    @overload
    def eq(self: Iterum[object], other: Iterable[SupportsRichComparison], /) -> bool:
        ...

    def eq(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> bool:
        """
        Determines if the elements of this Iterator are equal to those of another.

        Examples:

            >>> assert iterum([1]).eq([1])
            >>> assert not iterum([1]).eq([1, 2])
        """
        cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
        return cmp == Ordering.Equal

    def filter(
        self: Iterum[T_co], predicate: Callable[[T_co], object], /
    ) -> Filter[T_co]:
        """
        Creates an iterum which uses a closure to determine if an element
        should be yielded.

        Given an element the closure must return `True` or `False`. The returned
        iterum will yield only the elements for which the closure returns `True`.

        Examples:

            >>> a = [0, 1, 2]
            >>> it = iterum(a).filter(lambda x: x > 0)
            >>> assert it.next() == Some(1)
            >>> assert it.next() == Some(2)
            >>> assert it.next() == nil

        Note that `it.filter(f).next()` is equivalent to `it.find(f)`.
        """
        return Filter(self, predicate)

    def filter_map(
        self: Iterum[T_co], predicate: Callable[[T_co], Option[U]], /
    ) -> FilterMap[U]:
        """
        Creates an iterum that both filters and maps.

        The returned iterum yields only the values for which the supplied
        closure returns [Some(value)][iterum.Some].

        [filter_map][iterum.Iterum.filter_map] can be used to make chains of
        [filter][iterum.Iterum.filter] and [map][iterum.Iterum.map] more concise.

        Examples:

            >>> def parse2int(x: str) -> Option[int]:
            ...     try:
            ...         value = int(x)
            ...     except ValueError:
            ...         return nil
            ...     else:
            ...         return Some(value)
            ...
            >>> a = ["1", "two", "NaN", "four", "5"]
            >>> it = iterum(a).filter_map(parse2int)
            >>> assert it.next() == Some(1)
            >>> assert it.next() == Some(5)
            >>> assert it.next() == nil
        """
        return FilterMap(self, predicate)

    def find(self, predicate: Callable[[T_co], object], /) -> Option[T_co]:
        """
        Searches for an element of an iterum that satisfies a predicate.

        [find()][iterum.Iterum.find] takes a closure that returns `True` or
        `False`. It applies this closure to each element of the iterum, and if
        any of them return `True`, then [find()][iterum.Iterum.find] returns
        [Some(element)][iterum.Some]. If they all return `False`, it returns
        [nil][iterum.nil].

        [find()][iterum.Iterum.find] is short-circuiting; in other words, it
        will stop processing as soon as the closure returns `True`.

        If you need the index of the element, see [position()][iterum.Iterum.position].

        Examples:

            >>> a = [1, 2, 3]
            >>> assert iterum(a).find(lambda x: x == 2) == Some(2)
            >>> assert iterum(a).find(lambda x: x == 5) == nil

            Stopping at the first `True`:
            >>> it = iterum([1, 2, 3])
            >>> assert it.find(lambda x: x == 2) == Some(2)
            >>> assert it.next() == Some(3)

        Note that `it.find(f)` is equivalent to `it.filter(f).next()`.
        """
        for x in self:
            if predicate(x):
                return Some(x)
        return nil

    def find_map(self, predicate: Callable[[T_co], Option[U]], /) -> Option[U]:
        """
        Applies function to the elements of iterum and returns the first
        non-nil result.

        Examples:

            >>> def parse2int(x: str) -> Option[int]:
            ...     try:
            ...         value = int(x)
            ...     except ValueError:
            ...         return nil
            ...     else:
            ...         return Some(value)
            ...
            >>> a = ["lol", "NaN", "2", "5"]
            >>> first_number = iterum(a).find_map(parse2int)
            >>> assert first_number == Some(2)

        Note that `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`.
        """
        return self.filter_map(predicate).next()

    def flat_map(self, f: Callable[[T_co], Iterable[U]], /) -> FlatMap[U]:
        """
        Creates an iterum that works like map, but flattens nested structure.

        The [map][iterum.Iterum.map] adapter is very useful, but only when the
        closure argument produces values. If it produces an iterum instead,
        there’s an extra layer of indirection.
        [flat_map()][iterum.Iterum.flat_map] will remove this extra layer on its own.

        You can think of `flat_map(f)` as the semantic equivalent of mapping, and
        then flattening as in `map(f).flatten()`.

        Examples:

            >>> words = ["alpha", "beta", "gamma"]
            >>> merged = iterum(words).flat_map(iterum).collect("".join)
            >>> assert merged == "alphabetagamma"
        """
        return FlatMap(self, f)

    def flatten(self: Iterum[Iterable[U]]) -> Flatten[U]:
        """
        Creates an iterum that flattens nested structure.

        This is useful when you have an iterum of iterables and you want to
        remove one level of indirection.

        Examples:

            >>> data = [[1, 2, 3, 4], [5, 6]]
            >>> flattened = iterum(data).flatten().collect(list)
            >>> assert flattened == [1, 2, 3, 4, 5, 6]

            Mapping and then flattening:
            >>> words = ["alpha", "beta", "gamma"]
            >>> merged = iterum(words).map(iterum).flatten().collect("".join)
            >>> assert merged == "alphabetagamma"
        """
        return Flatten(self)

    def fold(self, init: U, f: Callable[[U, T_co], U], /) -> U:
        """
        Folds every element into an accumulator by applying an operation,
        returning the final result.

        [fold()][iterum.Iterum.fold] takes two arguments: an initial value, and
        a closure with two arguments: an ‘accumulator’, and an element. The
        closure returns the value that the accumulator should have for the next iteration.

        The initial value is the value the accumulator will have on the first call.

        After applying this closure to every element of the iterum, fold()
        returns the accumulator.

        Examples:

            >>> a = [1, 2, 3]
            >>> sum = iterum(a).fold(0, lambda acc, x: acc + x)
            >>> assert sum == 6

            Let's walk through each step of the iteration here:

            | element | acc | x | result |
            | ------- | --- | - | ------ |
            |         |  0  |   |        |
            |   1     |  0  | 1 |   1    |
            |   2     |  1  | 2 |   3    |
            |   3     |  3  | 3 |   6    |

            And so, our final result, 6.


        fold is left-associative:

            ```python
            >>> numbers = [1, 2, 3, 4, 5]
            >>> result = iterum(numbers).fold("0", lambda acc, x: f"({acc} + {x})")
            >>> assert result == "(((((0 + 1) + 2) + 3) + 4) + 5)"

            ```
        """
        acc = init
        for x in self:
            acc = f(acc, x)
        return acc

    def for_each(self, f: Callable[[T_co], object], /) -> None:
        """
        Calls a closure on each element of an iterum.

        For loops are more idiomatic... but who cares!

        Examples:

            >>> v = []
            >>> seq(5).map(lambda x: x * 2 + 1).for_each(v.append)
            >>> assert v == [1, 3, 5, 7, 9]
        """
        for x in self:
            f(x)

    def fuse(self) -> Fuse[T_co]:
        """
        Creates an iterum which ends after the first [nil][iterum.nil].

        After an iterum returns [nil][iterum.nil], future calls may or may not
        yield [Some(T)][iterum.Some] again. [fuse()][iterum.Iterum.fuse] adapts
        an iterum, ensuring that after a [nil][iterum.nil] is given, it will
        always return [nil][iterum.nil] forever.

        Examples:

            >>> class Alternator(Iterator[int]):
            ...     def __init__(self) -> None:
            ...         self.i = 0
            ...     def __next__(self) -> int:
            ...         self.i += 1
            ...         if self.i % 5:
            ...             return self.i
            ...         else:
            ...             raise StopIteration()

            >>> it = iterum(Alternator())
            >>> assert list(it) == [1, 2, 3, 4]
            >>> assert list(it) == [6, 7, 8, 9]
            >>> assert list(it) == [11, 12, 13, 14]

            >>> it = it.fuse()
            >>> assert list(it) == [16, 17, 18, 19]
            >>> assert list(it) == []
            >>> assert list(it) == []
        """
        return Fuse(self)

    @overload
    def ge(self: Iterum[SupportsRichComparison], other: Iterable[object], /) -> bool:
        ...

    @overload
    def ge(self: Iterum[object], other: Iterable[SupportsRichComparison], /) -> bool:
        ...

    def ge(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> bool:
        """
        Determines if the elements of this Iterator are lexicographically
        greater than or equal to those of another.

        Examples:

            >>> assert iterum([1]).ge([1])
            >>> assert not iterum([1]).ge([1, 2])
            >>> assert iterum([1, 2]).ge([1])
            >>> assert iterum([1, 2]).ge([1, 2])
        """
        cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
        return cmp in (Ordering.Greater, Ordering.Equal)

    @overload
    def gt(self: Iterum[SupportsRichComparison], other: Iterable[object], /) -> bool:
        ...

    @overload
    def gt(self: Iterum[object], other: Iterable[SupportsRichComparison], /) -> bool:
        ...

    def gt(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> bool:
        """
        Determines if the elements of this Iterator are lexicographically
        greater than those of another.

        Examples:

            >>> assert not iterum([1]).gt([1])
            >>> assert not iterum([1]).gt([1, 2])
            >>> assert iterum([1, 2]).gt([1])
            >>> assert not iterum([1, 2]).gt([1, 2])
        """
        cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
        return cmp == Ordering.Greater

    def inspect(self, f: Callable[[T_co], object], /) -> Inspect[T_co]:
        """
        Does something with each element of an iterum, passing the value on.

        When using iterums, you’ll often chain several of them together. While
        working on such code, you might want to check out what’s happening at
        various parts in the pipeline. To do that, insert a call to
        [inspect()][iterum.Iterum.inspect].

        Examples:

            >>> s = (
            ...    iterum([1, 4, 2, 3])
            ...    .inspect(lambda x: print(f"about to filter: {x}"))
            ...    .filter(lambda x: x % 2 == 0)
            ...    .inspect(lambda x: print(f"made it through filter: {x}"))
            ...    .fold(0, lambda sum, i: sum + i)
            ... )
            ...
            about to filter: 1
            about to filter: 4
            made it through filter: 4
            about to filter: 2
            made it through filter: 2
            about to filter: 3
            >>> s
            6

            >>> a = [1, 2, 3]
            >>> b = []
            >>> c = (
            ...     iterum(a)
            ...     .map(lambda x: x * 2)
            ...     .inspect(b.append)
            ...     .take_while(lambda x: x < 5)
            ...     .collect(list)
            ... )
            >>> assert b == [2, 4, 6]
            >>> assert c == [2, 4]
        """
        return Inspect(self, f)

    def last(self) -> Option[T_co]:
        """
        Consumes the iterum, returning the last element.

        This method will evaluate the iterum until it returns
        [nil][iterum.nil]. While doing so, it keeps track of the current
        element. After [nil][iterum.nil] is returned, last() will then return
        the last element it saw.

        Examples:

            >>> assert iterum([1, 2, 3]).last() == Some(3)
            >>> assert iterum([1, 2, 3, 4, 5]).last() == Some(5)
        """
        last = nil
        while (nxt := self.next()) is not nil:
            last = nxt

        return last

    @overload
    def le(self: Iterum[SupportsRichComparison], other: Iterable[object], /) -> bool:
        ...

    @overload
    def le(self: Iterum[object], other: Iterable[SupportsRichComparison], /) -> bool:
        ...

    def le(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> bool:
        """
        Determines if the elements of this Iterator are lexicographically less
        or equal to those of another.

        Examples:

            >>> assert iterum([1]).le([1])
            >>> assert iterum([1]).le([1, 2])
            >>> assert not iterum([1, 2]).le([1])
            >>> assert iterum([1, 2]).le([1, 2])
        """
        cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
        return cmp in (Ordering.Less, Ordering.Equal)

    @overload
    def lt(self: Iterum[SupportsRichComparison], other: Iterable[object], /) -> bool:
        ...

    @overload
    def lt(self: Iterum[object], other: Iterable[SupportsRichComparison], /) -> bool:
        ...

    def lt(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> bool:
        """
        Determines if the elements of this Iterator are lexicographically less
        than those of another.

        Examples:

            >>> assert not iterum([1]).lt([1])
            >>> assert iterum([1]).lt([1, 2])
            >>> assert not iterum([1, 2]).lt([1])
            >>> assert not iterum([1, 2]).lt([1, 2])
        """
        cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
        return cmp == Ordering.Less

    def map(self, f: Callable[[T_co], U], /) -> Map[U]:
        """
        Takes a closure and creates an iterum which calls that closure on
        each element.

        [map()][iterum.Iterum.map] transforms one iterum into another, by
        means of its argument. It produces a new iterum which calls this
        closure on each element of the original iterum.

        Examples:

            >>> a = [1, 2, 3]
            >>> itr = iterum(a).map(lambda x: x * 2)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == Some(4)
            >>> assert itr.next() == Some(6)
            >>> assert itr.next() == nil
        """
        return Map(self, f)

    def map_while(self, predicate: Callable[[T_co], Option[U]], /) -> MapWhile[U]:
        """
        Creates an iterum that both yields elements based on a predicate and maps.

        [map_while()][iterum.Iterum.map_while] takes a closure as an argument.
        It will call this closure on each element of the iterum, and yield
        elements while it returns [Some(_)][iterum.Some].

        Examples:

            >>> from functools import partial
            >>> def checked_div(num: int, dem: int) -> Option[int]:
            ...    try:
            ...        return Some(num // dem)
            ...    except ZeroDivisionError:
            ...        return nil
            ...
            >>> a = [-1, 4, 0, 1]
            >>> it = iterum(a).map_while(partial(checked_div, 16))
            >>> assert it.next() == Some(-16)
            >>> assert it.next() == Some(4)
            >>> assert it.next() == nil


            Stops after first [nil][iterum.nil]:
            >>> a = [0, 1, 2, -3, 4, 5, -6]
            >>> it = iterum(a).map_while(lambda x: Some(x) if x >= 0 else nil)
            >>> vec = it.collect(list)
            >>> assert vec == [0, 1, 2]
            >>> assert it.next() == nil
        """
        return MapWhile(self, predicate)

    def max(
        self: Iterum[SupportsRichComparisonT],
    ) -> Option[SupportsRichComparisonT]:
        """
        Returns the maximum element of an iterum.

        If several elements are equally maximum, the last element is returned.
        If the iterum is empty, [nil][iterum.nil] is returned.

        Examples:

            >>> assert iterum([1, 2, 3]).max() == Some(3)
            >>> assert iterum([]).max() == nil
        """
        try:
            return Some(builtins.max(self))
        except ValueError:
            return nil

    def max_by(self, compare: Callable[[T_co, T_co], Ordering], /) -> Option[T_co]:
        """
        Returns the element that gives the maximum value with respect to the
        specified comparison function.

        If several elements are equally maximum, the last element is returned.
        If the iterum is empty, [nil][iterum.nil] is returned.

        Examples:

            >>> a = [-3, 0, 1, 5, -10]
            >>> assert iterum(a).max_by(Ordering.cmp).unwrap() == 5
        """
        max_ = self.next()
        if max_ is nil:
            return nil
        else:
            max_ = max_.unwrap()

        for nxt in self:
            if compare(max_, nxt) is Ordering.Less:
                max_ = nxt

        return Some(max_)

    def max_by_key(
        self, f: Callable[[T_co], SupportsRichComparison], /
    ) -> Option[T_co]:
        """
        Returns the element that gives the maximum value from the specified function.

        If several elements are equally maximum, the last element is returned.
        If the iterum is empty, [nil][iterum.nil] is returned.

        Examples:

            >>> a = [-3, 0, 1, 5, -10]
            >>> assert iterum(a).max_by_key(abs).unwrap() == -10
        """

        def compare(x, y) -> Ordering:
            fx = f(x)
            fy = f(y)
            return Ordering.cmp(fx, fy)

        return self.max_by(compare)

    def min(
        self: Iterum[SupportsRichComparisonT],
    ) -> Option[SupportsRichComparisonT]:
        """
        Returns the minimum element of an iterum.

        If several elements are equally minimum, the first element is returned.
        If the iterum is empty, [nil][iterum.nil] is returned.

        Examples:

            >>> assert iterum([1, 2, 3]).min() == Some(1)
            >>> assert iterum([]).min() == nil
        """
        try:
            return Some(builtins.min(self))
        except ValueError:
            return nil

    def min_by(self, compare: Callable[[T_co, T_co], Ordering], /) -> Option[T_co]:
        """
        Returns the element that gives the minimum value with respect to the
        specified comparison function.

        If several elements are equally minimum, the first element is returned.
        If the iterum is empty, [nil][iterum.nil] is returned.

        Examples:

            >>> a = [-3, 0, 1, 5, -10]
            >>> assert iterum(a).min_by(Ordering.cmp).unwrap() == -10
        """
        min_ = self.next()
        if min_ is nil:
            return nil
        else:
            min_ = min_.unwrap()

        for nxt in self:
            if compare(min_, nxt) is Ordering.Greater:
                min_ = nxt

        return Some(min_)

    def min_by_key(
        self, f: Callable[[T_co], SupportsRichComparison], /
    ) -> Option[T_co]:
        """
        Returns the element that gives the minimum value from the specified function.

        If several elements are equally minimum, the first element is returned.
        If the iterum is empty, [nil][iterum.nil] is returned.

        Examples:

            >>> a = [-3, 0, 1, 5, -10]
            >>> assert iterum(a).min_by_key(abs).unwrap() == 0
        """

        def compare(x, y) -> Ordering:
            fx = f(x)
            fy = f(y)
            return Ordering.cmp(fx, fy)

        return self.min_by(compare)

    @overload
    def ne(self: Iterum[SupportsRichComparison], other: Iterable[object], /) -> bool:
        ...

    @overload
    def ne(self: Iterum[object], other: Iterable[SupportsRichComparison], /) -> bool:
        ...

    def ne(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> bool:
        """
        Determines if the elements of this Iterator are not equal to those of another.

        Examples:

            >>> assert not iterum([1]).ne([1])
            >>> assert iterum([1]).ne([1, 2])
        """
        eq = self.eq(other)  # type: ignore | reason: ask for forgiveness not permission
        return not eq

    def nth(self, n: int, /) -> Option[T_co]:
        """
        Returns the nth element of the iterum.

        Like most indexing operations, the count starts from zero, so [nth(0)][iterum.Iterum.nth]
        returns the first value, [nth(1)][iterum.Iterum.nth] the second, and so on.

        Note that all preceding elements, as well as the returned element, will
        be consumed from the iterum. That means that the preceding elements
        will be discarded, and also that calling [nth(0)][iterum.Iterum.nth] multiple times on the
        same iterum will return different elements.

        [nth()][iterum.Iterum.nth] will return [nil][iterum.nil] if n is greater
        than or equal to the length of the iterum.

        Examples:

            >>> a = [1, 2, 3]
            >>> assert iterum(a).nth(1) == Some(2)

            Calling [nth][iterum.Iterum.nth] multiple times doesn't rewind the iterum:
            >>> itr = iterum([1, 2, 3])
            >>> assert itr.nth(1) == Some(2)
            >>> assert itr.nth(1) == nil

            Returns [nil][iterum.nil] if there are less than `n + 1` elements:
            >>> itr = iterum([1, 2, 3])
            >>> assert itr.nth(3) == nil
        """
        for i, x in enumerate(self):
            if i > n:
                return nil
            if i == n:
                return Some(x)
        return nil

    @overload
    def partial_cmp(
        self: Iterum[SupportsRichComparison], other: Iterable[object], /
    ) -> Some[Ordering]:
        ...

    @overload
    def partial_cmp(
        self: Iterum[object], other: Iterable[SupportsRichComparison], /
    ) -> Some[Ordering]:
        ...

    @overload
    def partial_cmp(self: Iterum[object], other: Iterable[object], /) -> Nil:
        ...

    def partial_cmp(
        self: Iterum[SupportsRichComparison] | Iterum[object],
        other: Iterable[object] | Iterable[SupportsRichComparison],
        /,
    ) -> Option[Ordering]:
        """
        Lexicographically compares the PartialOrd elements of this Iterator with
        those of another. The comparison works like short-circuit evaluation,
        returning a result without comparing the remaining elements. As soon as
        an order can be determined, the evaluation stops and a result is returned.

        Examples:

            >>> assert iterum([1]).partial_cmp([1]) == Some(Ordering.Equal)
            >>> assert iterum([1, 2]).partial_cmp([1]) == Some(Ordering.Greater)
            >>> assert iterum([1]).partial_cmp([1, 2]) == Some(Ordering.Less)

            Results are determined by the order of evaluation:
            >>> assert iterum([1, None]).partial_cmp([2, nil]) == Some(Ordering.Less)
            >>> assert iterum([2, None]).partial_cmp([1, nil]) == Some(Ordering.Greater)
            >>> assert iterum([None, 1]).partial_cmp([2, None]) == nil
        """
        try:
            value = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
        except TypeError:
            return nil
        else:
            return Some(value)

    @overload
    def partition(
        self, f: Callable[[T_co], object], /
    ) -> tuple[list[T_co], list[T_co]]:
        ...

    @overload
    def partition(
        self, f: Callable[[T_co], object], container: type[list], /
    ) -> tuple[list[T_co], list[T_co]]:
        ...

    @overload
    def partition(
        self, f: Callable[[T_co], object], container: type[set], /
    ) -> tuple[set[T_co], set[T_co]]:
        ...

    @overload
    def partition(
        self, f: Callable[[T_co], object], container: type[tuple], /
    ) -> tuple[tuple[T_co, ...], tuple[T_co, ...]]:
        ...

    @overload
    def partition(
        self: Iterum[tuple[U, V]], f: Callable[[T_co], object], container: type[dict], /
    ) -> tuple[dict[U, V], dict[U, V]]:
        ...

    @overload
    def partition(
        self, f: Callable[[T_co], object], container: Callable[[Iterable[T_co]], U], /
    ) -> tuple[U, U]:
        ...

    def partition(  # type: ignore
        self,
        f: Callable[[T_co], object],
        container: Callable[[Iterable[T_co]], U] = list,
        /,
    ) -> tuple[U, U]:
        """
        Consumes an iterum, creating two collections from it.

        The predicate passed to [partition()][iterum.Iterum.partition] can
        return `True`, or `False`. [partition()][iterum.Iterum.partition]
        returns a pair, all of the elements for which it returned `True`, and
        all of the elements for which it returned `False`.

        Examples:

            >>> a = [1, 2, 3]
            >>> even, odd = iterum(a).partition(lambda n: n % 2 == 0)
            >>> assert even == [2]
            >>> assert odd == [1, 3]
        """
        matches, notmatches = [], []
        for x in self:
            matches.append(x) if f(x) else notmatches.append(x)

        return container(matches), container(notmatches)

    def peekable(self) -> Peekable[T_co]:
        """
        Creates an iterum which provides a peek attribute for viewing
        and setting the next element of the iterum without consuming it.

        Examples:

            >>> xs = [1, 2, 3]
            >>> itr = iterum(xs).peekable()
            >>> assert itr.peek == Some(1)
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.peek == Some(3)
            >>> assert itr.peek == Some(3)
            >>> assert itr.next() == Some(3)
            >>> assert itr.peek == nil
            >>> assert itr.next() == nil

            >>> xs = [1, 2, 3]
            >>> itr = iterum(xs).peekable()
            >>> assert itr.peek == Some(1)
            >>> assert itr.peek == Some(1)
            >>> assert itr.next() == Some(1)
            >>> assert itr.peek == Some(2)
            >>> itr.peek = 1000
            >>> assert list(itr) == [1000, 3]
        """
        return Peekable(self)

    def position(self, predicate: Callable[[T_co], object], /) -> Option[int]:
        """
        Searches for an element in an iterum, returning its index.

        [position()][iterum.Iterum.position] takes a closure that returns `True`
        or `False`. It applies this closure to each element of the iterum, and
        if one of them returns `True`, then [position()][iterum.Iterum.position]
        returns [Some(index)][iterum.Some]. If all of them return `False`, it
        returns [nil][iterum.nil].

        [position()][iterum.Iterum.position] is short-circuiting; in other
        words, it will stop processing as soon as it finds a `True`.

        Examples:

            >>> a = [1, 2, 3]
            >>> assert iterum(a).position(lambda x: x == 2) == Some(1)
            >>> assert iterum(a).position(lambda x: x == 5) == nil


            >>> it = iterum([1, 2, 3, 4])
            >>> assert it.position(lambda x: x >= 2) == Some(1)
            >>> assert it.next() == Some(3)
            >>> assert it.position(lambda x: x == 4) == Some(0)
        """
        for i, x in enumerate(self):
            if predicate(x):
                return Some(i)
        return nil

    def product(self: Iterum[SupportsMulT]) -> Option[SupportsMulT]:
        """
        Iterates over the entire iterum, multiplying all the elements

        An empty iterum returns [nil][iterum.nil].

        Examples:

            >>> def factorial(n: int) -> int:
            ...     return seq(1, n + 1).product().unwrap_or(1)
            ...
            >>> assert factorial(0) == 1
            >>> assert factorial(1) == 1
            >>> assert factorial(5) == 120
        """
        return self.reduce(lambda acc, x: acc * x)

    def reduce(self, f: Callable[[T_co, T_co], T_co], /) -> Option[T_co]:
        """
        Reduces the elements to a single one, by repeatedly applying a reducing operation.

        If the iterum is empty, returns [nil][iterum.nil]; otherwise, returns
        the result of the reduction.

        The reducing function is a closure with two arguments: an ‘accumulator’,
        and an element. For iterums with at least one element, this is the
        same as [fold()][iterum.Iterum.fold] with the first element of the
        iterum as the initial accumulator value, folding every subsequent
        element into it.

        Examples:

            >>> reduced = seq(1, 10).reduce(lambda acc, e: acc + e).unwrap()
            >>> assert reduced == 45
        """
        first = self.next()
        if first is nil:
            return nil
        else:
            return Some(self.fold(first.unwrap(), f))

    def scan(self, init: U, f: Callable[[State[U], T_co], Option[V]], /) -> Scan[V]:
        """
        An iterum adapter which, like fold, holds internal state, but unlike
        fold, produces a new iterum.

        [scan()][iterum.Iterum.scan] takes two arguments: an initial value which
        seeds the internal state, and a closure with two arguments, the first
        being the internal state and the second an iterum element.
        The closure can assign to the internal state to share state between iterations.

        Examples:

            >>> itr = iterum([1, 2, 3, 4])
            >>> def scanner(state: State, x: int) -> Option[int]:
            ...     state.value *= x
            ...     if state.value > 6:
            ...         return nil
            ...     return Some(-state.value)
            ...
            >>> scan = itr.scan(1, scanner)
            >>> assert scan.next() == Some(-1)
            >>> assert scan.next() == Some(-2)
            >>> assert scan.next() == Some(-6)
            >>> assert scan.next() == nil
        """
        return Scan(self, init, f)

    # def size_hint ..., don't plan on implementing this one. Just use diterum if size is important

    def skip(self, n: int, /) -> Skip[T_co]:
        """
        Creates an iterum that skips the first n elements.

        [skip(n)][iterum.Iterum.skip] skips elements until n elements are
        skipped or the end of the iterum is reached (whichever happens first).
        After that, all the remaining elements are yielded. In particular, if
        the original iterum is too short, then the returned iterum is empty.

        Examples:

            >>> itr = iterum([1, 2, 3]).skip(2)
            >>> assert itr.next() == Some(3)
            >>> assert itr.next() == nil

            Skipping past end:
            >>> itr = iterum([1, 2, 3]).skip(10)
            >>> assert itr.next() == nil
            >>> assert itr.next() == nil
        """
        return Skip(self, n)

    def skip_while(self, predicate: Callable[[T_co], object], /) -> SkipWhile[T_co]:
        """
        Creates an iterum that skips elements based on a predicate.

        [skip_while()][iterum.Iterum.skip_while] takes a closure as an argument.
        It will call this closure on each element of the iterum, and ignore
        elements until it returns `False`.

        After `False` is returned, [skip_while()][iterum.Iterum.skip_while]’s
        job is over, and the rest of the elements are yielded.

        Examples:

            >>> itr = iterum([-1, 0, 1]).skip_while(lambda x: x < 0)
            >>> assert itr.next() == Some(0)
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == nil

            After first `False` condition is hit, no further elements are checked:
            >>> itr = iterum([-1, 0, 1, -3]).skip_while(lambda x: x < 0)
            >>> assert itr.next() == Some(0)
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(-3)
        """
        return SkipWhile(self, predicate)

    def step_by(self, step: int, /) -> StepBy[T_co]:
        """
        Creates an iterum starting at the same point, but stepping by the
        given amount at each iteration. This always includes the first element.

        Examples:

            >>> itr = iterum([0, 1, 2, 3, 4, 5]).step_by(2)
            >>> assert itr.next() == Some(0)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == Some(4)
            >>> assert itr.next() == nil
        """
        return StepBy(self, step)

    def sum(self: Iterum[SupportsSumNoDefaultT]) -> Option[SupportsSumNoDefaultT]:
        """
        Sums the elements of an iterum.

        Takes each element, adds them together, and returns the result.

        An empty iterum returns [nil][iterum.nil].

        Examples:

            >>> a = [1, 2, 3]
            >>> sum_ = iterum(a).sum().unwrap_or(0)
            >>> assert sum_ == 6

            >>> sum_ = iterum([]).sum().unwrap_or(0)
            >>> assert sum_ == 0
        """
        # NOTE: This forces users to pick a default or suffer the unwrapping consequences
        # a more reasonable interface since an implicit default isn't a thing
        first = self.next()
        if first is nil:
            return nil

        return Some(sum(self, start=first.unwrap()))

    def take(self, n: int, /) -> Take[T_co]:
        """
        Creates an iterum that yields the first n elements, or fewer if the
        underlying iterum ends sooner.

        [take(n)][iterum.Iterum.take] yields elements until n elements are
        yielded or the end of the iterum is reached (whichever happens first).
        The returned iterum is a prefix of length n if the original iterum
        contains at least n elements, otherwise it contains all of the (fewer
        than n) elements of the original iterum.

        Examples:

            >>> a = [1, 2, 3]
            >>> itr = iterum(a).take(2)
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == nil


            >>> a = [1, 2, 3]
            >>> itr = iterum(a).take(2)
            >>> assert list(itr) == [1, 2]
            >>> assert itr.next() == nil


            Truncate an infinite iterum:
            >>> itr = seq(...).take(3)
            >>> assert itr.next() == Some(0)
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == nil

            Taking more than you have:
            >>> itr = iterum([1, 2]).take(5)
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == nil
        """
        return Take(self, n)

    def take_while(self, predicate: Callable[[T_co], object], /) -> TakeWhile[T_co]:
        """
        Creates an iterum that yields elements based on a predicate.

        [take_while()][iterum.Iterum.take_while] takes a closure as an argument.
        It will call this closure on each element of the iterum, and yield
        elements while it returns `True`.

        After `False` is returned, [take_while()][iterum.Iterum.take_while]’s
        job is over, and the rest of the elements are ignored.

        Examples:

            >>> a = [-1, 0, 1]
            >>> itr = iterum(a).take_while(lambda x: x < 0)
            >>> assert itr.next() == Some(-1)
            >>> assert itr.next() == nil

            Stop after first `False`:
            >>> a = [-1, 0, 1, -2]
            >>> itr = iterum(a).take_while(lambda x: x < 0)
            >>> assert itr.next() == Some(-1)
            >>> assert itr.next() == nil
        """
        return TakeWhile(self, predicate)

    def try_fold(
        self,
        init: U,
        f: Callable[[U, T_co], U],
        /,
        *,
        exception: type[BaseException] | tuple[type[BaseException], ...] = Exception,
    ) -> Option[U]:
        """
        An iterum method that applies a function as long as it returns
        successfully, producing a single, final value.

        [try_fold()][iterum.Iterum.try_fold] takes two arguments: an initial
        value, and a closure with two arguments: an ‘accumulator’, and an
        element. The closure either returns successfully, with the value that
        the accumulator should have for the next iteration, or it raises an
        exception which short-circuits the iteration.

        Examples:

            >>> def checked_add_i8(lhs: int, rhs: int) -> int:
            ...     value = lhs + rhs
            ...     if -128 <= value <= 127:
            ...         return value
            ...     else:
            ...         raise ValueError("Overflow!")
            ...
            >>> a = [1, 2, 3]
            >>> sum = iterum(a).try_fold(0, checked_add_i8)
            >>> assert sum == Some(6)

            short-circuit after a failure:
            >>> it = iterum([10, 20, 30, 100, 40, 50])
            >>> sum = it.try_fold(0, checked_add_i8)
            >>> assert sum == nil
            >>> assert list(it) == [40, 50]
        """
        acc = init
        for x in self:
            try:
                acc = f(acc, x)
            except exception:
                return nil

        return Some(acc)

    # This would be the same as a for each...
    # def try_for_each(self, f: Callable[[T], object], /) -> None:
    #     for x in self:
    #         try:
    #             f(x)
    #         except Exception:
    #             return

    @overload
    def unzip(self: Iterum[tuple[U, V]], /) -> tuple[list[U], list[V]]:
        ...

    @overload
    def unzip(
        self: Iterum[tuple[U, V]], container: type[list], /
    ) -> tuple[list[U], list[V]]:
        ...

    @overload
    def unzip(
        self: Iterum[tuple[U, V]], container: type[set], /
    ) -> tuple[set[U], set[V]]:
        ...

    @overload
    def unzip(
        self: Iterum[tuple[U, V]], container: type[tuple], /
    ) -> tuple[tuple[U, ...], tuple[V, ...]]:
        ...

    @overload
    def unzip(
        self: Iterum[tuple[object, object]],
        container: Callable[[Iterable[object]], U],
        /,
    ) -> tuple[U, U]:
        ...

    def unzip(
        self: Iterum[tuple[object, object]],
        container: Callable[[Iterable[object]], U] = list,
        /,
    ) -> tuple[U, U]:
        """
        Converts an iterum of pairs into a pair of containers.

        [unzip()][iterum.Iterum.unzip] consumes an entire iterum of pairs,
        producing two collections: one from the left elements of the pairs, and
        one from the right elements.

        This function is, in some sense, the opposite of [zip][iterum.Iterum.zip].

        Examples:

            >>> a = [(1, 2), (3, 4), (5, 6)]
            >>> left, right = iterum(a).unzip()
            >>> assert left == [1, 3, 5]
            >>> assert right == [2, 4, 6]
        """
        left, right = map(container, zip(*self))
        return left, right

    def zip(self, other: Iterable[U], /) -> Zip[T_co, U]:
        """
        ‘Zips up’ two iterables into a single iterum of pairs.

        [zip()][iterum.Iterum.zip] returns a new iterum that will iterate over
        two other iterables, returning a tuple where the first element comes
        from the first iterable, and the second element comes from the second iterable.

        If either iterable returns [nil][iterum.nil], next from the zipped
        iterum will return [nil][iterum.nil]. If the zipped iterum has no
        more elements to return then each further attempt to advance it will
        first try to advance the first iterable at most one time and if it still
        yielded an item try to advance the second iterable at most one time.

        To ‘undo’ the result of zipping up two iterables, see [unzip][iterum.Iterum.unzip].

        Examples:

            >>> a1 = [1, 2, 3]
            >>> a2 = [4, 5, 6]
            >>> itr = iterum(a1).zip(a2)
            >>> assert itr.next() == Some((1, 4))
            >>> assert itr.next() == Some((2, 5))
            >>> assert itr.next() == Some((3, 6))
            >>> assert itr.next() == nil

            zip smaller with larger:
            >>> inf_itr = seq(...)
            >>> foo_itr = iterum("foo")
            >>> zip_itr = foo_itr.zip(inf_itr)
            >>> assert zip_itr.next() == Some(("f", 0))
            >>> assert zip_itr.next() == Some(("o", 1))
            >>> assert zip_itr.next() == Some(("o", 2))
            >>> assert zip_itr.next() == nil
            >>> assert foo_itr.next() == nil
            >>> assert inf_itr.next() == Some(3)

            zip larger with smaller:
            >>> inf_itr = seq(...)
            >>> foo_itr = iterum("foo")
            >>> zip_itr = inf_itr.zip(foo_itr)
            >>> assert zip_itr.next() == Some((0, "f"))
            >>> assert zip_itr.next() == Some((1, "o"))
            >>> assert zip_itr.next() == Some((2, "o"))
            >>> assert zip_itr.next() == nil
            >>> assert foo_itr.next() == nil
            >>> assert inf_itr.next() == Some(4)
        """
        return Zip(self, other)

next() -> Option[T_co] abstractmethod

Required method.

Advances the iterum and returns the next value.

Returns nil when iteration is finished. Individual iterum implementations may choose to resume iteration, and so calling next() again may or may not eventually start returning Some(Item) again at some point.

Examples:

>>> itr = iterum([1, 2, 3])

A call to next() returns the next value...

>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == Some(3)

... and then nil once it's over.

>>> assert itr.next() == nil

More calls may or may not return nil. Here, they always will.

>>> assert itr.next() == nil
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
@abstractmethod
def next(self) -> Option[T_co]:
    """
    Required method.

    Advances the iterum and returns the next value.

    Returns [nil][iterum.nil] when iteration is finished.
    Individual iterum implementations may choose to resume iteration,
    and so calling [next()][iterum.Iterum.next] again may or may not eventually start returning
    [Some(Item)][iterum.Some] again at some point.

    Examples:

        >>> itr = iterum([1, 2, 3])

        A call to next() returns the next value...
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == Some(3)

        ... and then [nil][iterum.nil] once it's over.
        >>> assert itr.next() == nil

        More calls may or may not return [nil][iterum.nil]. Here, they always will.
        >>> assert itr.next() == nil
        >>> assert itr.next() == nil
    """
    return nil

all(f: Callable[[T_co], object]) -> bool

Tests if every element of the iterum matches a predicate.

all() takes a closure that returns True or False. It applies this closure to each element of the iterum, and if they all return True, then so does all(). If any of them return False, it returns False.

all() is short-circuiting; in other words, it will stop processing as soon as it finds a False, given that no matter what else happens, the result will also be False.

An empty iterum returns True.

Examples:

>>> a = [1, 2, 3]
>>> assert iterum(a).all(lambda x: x > 0)
>>> assert not iterum(a).all(lambda x: x > 2)

Stopping at the first False:

>>> itr = iterum([1, 2, 3])
>>> assert not itr.all(lambda x: x != 2)
>>> assert itr.next() == Some(3)
Source code in iterum/_iterum.py
def all(self, f: Callable[[T_co], object], /) -> bool:
    """
    Tests if every element of the iterum matches a predicate.

    [all()][iterum.Iterum.all] takes a closure that returns `True` or `False`.
    It applies this closure to each element of the iterum,
    and if they all return `True`, then so does [all()][iterum.Iterum.all].
    If any of them return `False`, it returns `False`.

    [all()][iterum.Iterum.all] is short-circuiting; in other words, it will
    stop processing as soon as it finds a `False`, given that no matter
    what else happens, the result will also be `False`.

    An empty iterum returns `True`.

    Examples:

        >>> a = [1, 2, 3]
        >>> assert iterum(a).all(lambda x: x > 0)
        >>> assert not iterum(a).all(lambda x: x > 2)

        Stopping at the first `False`:
        >>> itr = iterum([1, 2, 3])
        >>> assert not itr.all(lambda x: x != 2)
        >>> assert itr.next() == Some(3)
    """
    return all(map(f, self))

any(f: Callable[[T_co], object]) -> bool

Tests if any element of the iterum matches a predicate.

any() takes a closure that returns True or False. It applies this closure to each element of the iterum, and if any of them return True, then so does any(). If they all return False, it returns False.

any() is short-circuiting; in other words, it will stop processing as soon as it finds a True, given that no matter what else happens, the result will also be True.

An empty iterum returns False.

Examples:

>>> a = [1, 2, 3]
>>> assert iterum(a).any(lambda x: x > 0)
>>> assert not iterum(a).any(lambda x: x > 5)

Stopping at the first True:

>>> itr = iterum([1, 2, 3])
>>> assert itr.any(lambda x: x != 2)

itr still has more elements.

>>> assert itr.next() == Some(2)
Source code in iterum/_iterum.py
def any(self, f: Callable[[T_co], object], /) -> bool:
    """
    Tests if any element of the iterum matches a predicate.

    [any()][iterum.Iterum.any] takes a closure that returns `True` or
    `False`. It applies this closure to each element of the iterum, and if
    any of them return `True`, then so does [any()][iterum.Iterum.any]. If
    they all return `False`, it returns `False`.

    [any()][iterum.Iterum.any] is short-circuiting; in other words, it will
    stop processing as soon as it finds a `True`, given that no matter what
    else happens, the result will also be `True`.

    An empty iterum returns `False`.

    Examples:

        >>> a = [1, 2, 3]
        >>> assert iterum(a).any(lambda x: x > 0)
        >>> assert not iterum(a).any(lambda x: x > 5)


        Stopping at the first `True`:
        >>> itr = iterum([1, 2, 3])
        >>> assert itr.any(lambda x: x != 2)

        itr still has more elements.
        >>> assert itr.next() == Some(2)
    """
    return any(map(f, self))

chain(other: Iterable[T_co]) -> Chain[T_co]

Takes two iterables and creates a new iterum over both in sequence.

chain() will return a new iterum which will first iterate over values from the first iteerable and then over values from the second iterable.

In other words, it links two iterables together, in a chain.

Examples:

>>> a1 = [1, 2, 3]
>>> a2 = [4, 5, 6]
>>> itr = iterum(a1).chain(a2)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == Some(3)
>>> assert itr.next() == Some(4)
>>> assert itr.next() == Some(5)
>>> assert itr.next() == Some(6)
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
def chain(self: Iterum[T_co], other: Iterable[T_co], /) -> Chain[T_co]:
    """
    Takes two iterables and creates a new iterum over both in sequence.

    [chain()][iterum.Iterum.chain] will return a new iterum which will
    first iterate over values from the first iteerable and then over values
    from the second iterable.

    In other words, it links two iterables together, in a chain.

    Examples:

        >>> a1 = [1, 2, 3]
        >>> a2 = [4, 5, 6]
        >>> itr = iterum(a1).chain(a2)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == Some(3)
        >>> assert itr.next() == Some(4)
        >>> assert itr.next() == Some(5)
        >>> assert itr.next() == Some(6)
        >>> assert itr.next() == nil
    """
    return Chain(self, other)

cmp(other: Iterable[object] | Iterable[SupportsRichComparison]) -> Ordering

Lexicographically compares the elements of this Iterator with those of another.

Examples:

>>> assert iterum([1]).cmp([1]) == Ordering.Equal
>>> assert iterum([1, 2]).cmp([1]) == Ordering.Greater
>>> assert iterum([1]).cmp([1, 2]) == Ordering.Less
Source code in iterum/_iterum.py
def cmp(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> Ordering:
    """
    Lexicographically compares the elements of this Iterator with those of
    another.

    Examples:

        >>> assert iterum([1]).cmp([1]) == Ordering.Equal
        >>> assert iterum([1, 2]).cmp([1]) == Ordering.Greater
        >>> assert iterum([1]).cmp([1, 2]) == Ordering.Less
    """
    other = iterum(other)
    while True:
        match self.next(), other.next():
            case Some(left), Some(right):
                if left > right:  # type: ignore | reason: ask for forgiveness not permission
                    return Ordering.Greater
                if left < right:  # type: ignore | reason: ask for forgiveness not permission
                    return Ordering.Less
                continue
            case Some(), Nil():
                return Ordering.Greater

            case Nil(), Some():
                return Ordering.Less

            case Nil(), Nil():
                return Ordering.Equal

            case _:
                raise AssertionError("Unreachable!")

collect(container: Callable[[Iterable[T_co]], U] = list) -> U

Transforms an iterum into a collection.

collect() takes a container which is responsible for mapping an iterable into any type. Most commonly this is a collection type such as list or set but could also be a function such as ''.join.

Examples:

>>> doubled = iterum([1, 2, 3]).map(lambda x: x * 2).collect(list)
>>> assert doubled == [2, 4, 6]

using join to collect an iterable of str

>>> assert iterum("test").map(str.upper).collect("".join) == "TEST"
Source code in iterum/_iterum.py
def collect(  # type: ignore
    self: Iterum[T_co], container: Callable[[Iterable[T_co]], U] = list, /
) -> U:
    """
    Transforms an iterum into a collection.

    [collect()][iterum.Iterum.collect] takes a container which is responsible
    for mapping an iterable into any type. Most commonly this is a collection
    type such as `list` or `set` but could also be a function such as `''.join`.

    Examples:

        >>> doubled = iterum([1, 2, 3]).map(lambda x: x * 2).collect(list)
        >>> assert doubled == [2, 4, 6]

        using `join` to collect an iterable of `str`
        >>> assert iterum("test").map(str.upper).collect("".join) == "TEST"
    """
    return container(self)

count() -> int

Consumes the iterum, counting the number of iterations and returning it.

This method will call next repeatedly until nil is encountered, returning the number of times it saw Some. Note that next has to be called at least once even if the iterum does not have any elements.

Examples:

>>> assert iterum([1, 2, 3]).count() == 3
>>> assert iterum([1, 2, 3, 4, 5]).count() == 5
Source code in iterum/_iterum.py
def count(self) -> int:
    """
    Consumes the iterum, counting the number of iterations and returning it.

    This method will call next repeatedly until [nil][iterum.nil] is
    encountered, returning the number of times it saw [Some][iterum.Some].
    Note that next has to be called at least once even if the iterum does
    not have any elements.

    Examples:

        >>> assert iterum([1, 2, 3]).count() == 3
        >>> assert iterum([1, 2, 3, 4, 5]).count() == 5
    """
    last = self.enumerate().last()
    return last.map_or(0, lambda last: last[0] + 1)

cycle() -> Cycle[T_co]

Repeats an iterum endlessly.

Instead of stopping at nil, the iterum will instead start again, from the beginning. After iterating again, it will start at the beginning again. And again. And again. Forever. Note that in case the original iterum is empty, the resulting iterum will also be empty.

Examples:

>>> a = [1, 2, 3]
>>> it = iterum(a).cycle()
>>> assert it.next() == Some(1)
>>> assert it.next() == Some(2)
>>> assert it.next() == Some(3)
>>> assert it.next() == Some(1)
>>> assert it.next() == Some(2)
>>> assert it.next() == Some(3)
>>> assert it.next() == Some(1)
Source code in iterum/_iterum.py
def cycle(self: Iterum[T_co], /) -> Cycle[T_co]:
    """
    Repeats an iterum endlessly.

    Instead of stopping at [nil][iterum.nil], the iterum will instead
    start again, from the beginning. After iterating again, it will start at
    the beginning again. And again. And again. Forever. Note that in case
    the original iterum is empty, the resulting iterum will also be empty.

    Examples:

        >>> a = [1, 2, 3]
        >>> it = iterum(a).cycle()
        >>> assert it.next() == Some(1)
        >>> assert it.next() == Some(2)
        >>> assert it.next() == Some(3)
        >>> assert it.next() == Some(1)
        >>> assert it.next() == Some(2)
        >>> assert it.next() == Some(3)
        >>> assert it.next() == Some(1)
    """
    return Cycle(self)

enumerate() -> Enumerate[T_co]

Creates an iterum which gives the current iteration count as well as the next value.

The iterum returned yields pairs (i, val), where i is the current index of iteration and val is the value returned by the iterum.

Examples:

>>> a = ["a", "b", "c"]
>>> it = iterum(a).enumerate()
>>> assert it.next() == Some((0, "a"))
>>> assert it.next() == Some((1, "b"))
>>> assert it.next() == Some((2, "c"))
>>> assert it.next() == nil
Source code in iterum/_iterum.py
def enumerate(self: Iterum[T_co], /) -> Enumerate[T_co]:
    """
    Creates an iterum which gives the current iteration count as well as
    the next value.

    The iterum returned yields pairs (i, val), where i is the current
    index of iteration and val is the value returned by the iterum.

    Examples:

        >>> a = ["a", "b", "c"]
        >>> it = iterum(a).enumerate()
        >>> assert it.next() == Some((0, "a"))
        >>> assert it.next() == Some((1, "b"))
        >>> assert it.next() == Some((2, "c"))
        >>> assert it.next() == nil
    """
    return Enumerate(self)

eq(other: Iterable[object] | Iterable[SupportsRichComparison]) -> bool

Determines if the elements of this Iterator are equal to those of another.

Examples:

>>> assert iterum([1]).eq([1])
>>> assert not iterum([1]).eq([1, 2])
Source code in iterum/_iterum.py
def eq(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> bool:
    """
    Determines if the elements of this Iterator are equal to those of another.

    Examples:

        >>> assert iterum([1]).eq([1])
        >>> assert not iterum([1]).eq([1, 2])
    """
    cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
    return cmp == Ordering.Equal

filter(predicate: Callable[[T_co], object]) -> Filter[T_co]

Creates an iterum which uses a closure to determine if an element should be yielded.

Given an element the closure must return True or False. The returned iterum will yield only the elements for which the closure returns True.

Examples:

>>> a = [0, 1, 2]
>>> it = iterum(a).filter(lambda x: x > 0)
>>> assert it.next() == Some(1)
>>> assert it.next() == Some(2)
>>> assert it.next() == nil

Note that it.filter(f).next() is equivalent to it.find(f).

Source code in iterum/_iterum.py
def filter(
    self: Iterum[T_co], predicate: Callable[[T_co], object], /
) -> Filter[T_co]:
    """
    Creates an iterum which uses a closure to determine if an element
    should be yielded.

    Given an element the closure must return `True` or `False`. The returned
    iterum will yield only the elements for which the closure returns `True`.

    Examples:

        >>> a = [0, 1, 2]
        >>> it = iterum(a).filter(lambda x: x > 0)
        >>> assert it.next() == Some(1)
        >>> assert it.next() == Some(2)
        >>> assert it.next() == nil

    Note that `it.filter(f).next()` is equivalent to `it.find(f)`.
    """
    return Filter(self, predicate)

filter_map(predicate: Callable[[T_co], Option[U]]) -> FilterMap[U]

Creates an iterum that both filters and maps.

The returned iterum yields only the values for which the supplied closure returns Some(value).

filter_map can be used to make chains of filter and map more concise.

Examples:

>>> def parse2int(x: str) -> Option[int]:
...     try:
...         value = int(x)
...     except ValueError:
...         return nil
...     else:
...         return Some(value)
...
>>> a = ["1", "two", "NaN", "four", "5"]
>>> it = iterum(a).filter_map(parse2int)
>>> assert it.next() == Some(1)
>>> assert it.next() == Some(5)
>>> assert it.next() == nil
Source code in iterum/_iterum.py
def filter_map(
    self: Iterum[T_co], predicate: Callable[[T_co], Option[U]], /
) -> FilterMap[U]:
    """
    Creates an iterum that both filters and maps.

    The returned iterum yields only the values for which the supplied
    closure returns [Some(value)][iterum.Some].

    [filter_map][iterum.Iterum.filter_map] can be used to make chains of
    [filter][iterum.Iterum.filter] and [map][iterum.Iterum.map] more concise.

    Examples:

        >>> def parse2int(x: str) -> Option[int]:
        ...     try:
        ...         value = int(x)
        ...     except ValueError:
        ...         return nil
        ...     else:
        ...         return Some(value)
        ...
        >>> a = ["1", "two", "NaN", "four", "5"]
        >>> it = iterum(a).filter_map(parse2int)
        >>> assert it.next() == Some(1)
        >>> assert it.next() == Some(5)
        >>> assert it.next() == nil
    """
    return FilterMap(self, predicate)

find(predicate: Callable[[T_co], object]) -> Option[T_co]

Searches for an element of an iterum that satisfies a predicate.

find() takes a closure that returns True or False. It applies this closure to each element of the iterum, and if any of them return True, then find() returns Some(element). If they all return False, it returns nil.

find() is short-circuiting; in other words, it will stop processing as soon as the closure returns True.

If you need the index of the element, see position().

Examples:

>>> a = [1, 2, 3]
>>> assert iterum(a).find(lambda x: x == 2) == Some(2)
>>> assert iterum(a).find(lambda x: x == 5) == nil

Stopping at the first True:

>>> it = iterum([1, 2, 3])
>>> assert it.find(lambda x: x == 2) == Some(2)
>>> assert it.next() == Some(3)

Note that it.find(f) is equivalent to it.filter(f).next().

Source code in iterum/_iterum.py
def find(self, predicate: Callable[[T_co], object], /) -> Option[T_co]:
    """
    Searches for an element of an iterum that satisfies a predicate.

    [find()][iterum.Iterum.find] takes a closure that returns `True` or
    `False`. It applies this closure to each element of the iterum, and if
    any of them return `True`, then [find()][iterum.Iterum.find] returns
    [Some(element)][iterum.Some]. If they all return `False`, it returns
    [nil][iterum.nil].

    [find()][iterum.Iterum.find] is short-circuiting; in other words, it
    will stop processing as soon as the closure returns `True`.

    If you need the index of the element, see [position()][iterum.Iterum.position].

    Examples:

        >>> a = [1, 2, 3]
        >>> assert iterum(a).find(lambda x: x == 2) == Some(2)
        >>> assert iterum(a).find(lambda x: x == 5) == nil

        Stopping at the first `True`:
        >>> it = iterum([1, 2, 3])
        >>> assert it.find(lambda x: x == 2) == Some(2)
        >>> assert it.next() == Some(3)

    Note that `it.find(f)` is equivalent to `it.filter(f).next()`.
    """
    for x in self:
        if predicate(x):
            return Some(x)
    return nil

find_map(predicate: Callable[[T_co], Option[U]]) -> Option[U]

Applies function to the elements of iterum and returns the first non-nil result.

Examples:

>>> def parse2int(x: str) -> Option[int]:
...     try:
...         value = int(x)
...     except ValueError:
...         return nil
...     else:
...         return Some(value)
...
>>> a = ["lol", "NaN", "2", "5"]
>>> first_number = iterum(a).find_map(parse2int)
>>> assert first_number == Some(2)

Note that iter.find_map(f) is equivalent to iter.filter_map(f).next().

Source code in iterum/_iterum.py
def find_map(self, predicate: Callable[[T_co], Option[U]], /) -> Option[U]:
    """
    Applies function to the elements of iterum and returns the first
    non-nil result.

    Examples:

        >>> def parse2int(x: str) -> Option[int]:
        ...     try:
        ...         value = int(x)
        ...     except ValueError:
        ...         return nil
        ...     else:
        ...         return Some(value)
        ...
        >>> a = ["lol", "NaN", "2", "5"]
        >>> first_number = iterum(a).find_map(parse2int)
        >>> assert first_number == Some(2)

    Note that `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`.
    """
    return self.filter_map(predicate).next()

flat_map(f: Callable[[T_co], Iterable[U]]) -> FlatMap[U]

Creates an iterum that works like map, but flattens nested structure.

The map adapter is very useful, but only when the closure argument produces values. If it produces an iterum instead, there’s an extra layer of indirection. flat_map() will remove this extra layer on its own.

You can think of flat_map(f) as the semantic equivalent of mapping, and then flattening as in map(f).flatten().

Examples:

>>> words = ["alpha", "beta", "gamma"]
>>> merged = iterum(words).flat_map(iterum).collect("".join)
>>> assert merged == "alphabetagamma"
Source code in iterum/_iterum.py
def flat_map(self, f: Callable[[T_co], Iterable[U]], /) -> FlatMap[U]:
    """
    Creates an iterum that works like map, but flattens nested structure.

    The [map][iterum.Iterum.map] adapter is very useful, but only when the
    closure argument produces values. If it produces an iterum instead,
    there’s an extra layer of indirection.
    [flat_map()][iterum.Iterum.flat_map] will remove this extra layer on its own.

    You can think of `flat_map(f)` as the semantic equivalent of mapping, and
    then flattening as in `map(f).flatten()`.

    Examples:

        >>> words = ["alpha", "beta", "gamma"]
        >>> merged = iterum(words).flat_map(iterum).collect("".join)
        >>> assert merged == "alphabetagamma"
    """
    return FlatMap(self, f)

flatten() -> Flatten[U]

Creates an iterum that flattens nested structure.

This is useful when you have an iterum of iterables and you want to remove one level of indirection.

Examples:

>>> data = [[1, 2, 3, 4], [5, 6]]
>>> flattened = iterum(data).flatten().collect(list)
>>> assert flattened == [1, 2, 3, 4, 5, 6]

Mapping and then flattening:

>>> words = ["alpha", "beta", "gamma"]
>>> merged = iterum(words).map(iterum).flatten().collect("".join)
>>> assert merged == "alphabetagamma"
Source code in iterum/_iterum.py
def flatten(self: Iterum[Iterable[U]]) -> Flatten[U]:
    """
    Creates an iterum that flattens nested structure.

    This is useful when you have an iterum of iterables and you want to
    remove one level of indirection.

    Examples:

        >>> data = [[1, 2, 3, 4], [5, 6]]
        >>> flattened = iterum(data).flatten().collect(list)
        >>> assert flattened == [1, 2, 3, 4, 5, 6]

        Mapping and then flattening:
        >>> words = ["alpha", "beta", "gamma"]
        >>> merged = iterum(words).map(iterum).flatten().collect("".join)
        >>> assert merged == "alphabetagamma"
    """
    return Flatten(self)

fold(init: U, f: Callable[[U, T_co], U]) -> U

Folds every element into an accumulator by applying an operation, returning the final result.

fold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and an element. The closure returns the value that the accumulator should have for the next iteration.

The initial value is the value the accumulator will have on the first call.

After applying this closure to every element of the iterum, fold() returns the accumulator.

Examples:

>>> a = [1, 2, 3]
>>> sum = iterum(a).fold(0, lambda acc, x: acc + x)
>>> assert sum == 6

Let's walk through each step of the iteration here:

element acc x result
0
1 0 1 1
2 1 2 3
3 3 3 6

And so, our final result, 6.

fold is left-associative
>>> numbers = [1, 2, 3, 4, 5]
>>> result = iterum(numbers).fold("0", lambda acc, x: f"({acc} + {x})")
>>> assert result == "(((((0 + 1) + 2) + 3) + 4) + 5)"
Source code in iterum/_iterum.py
def fold(self, init: U, f: Callable[[U, T_co], U], /) -> U:
    """
    Folds every element into an accumulator by applying an operation,
    returning the final result.

    [fold()][iterum.Iterum.fold] takes two arguments: an initial value, and
    a closure with two arguments: an ‘accumulator’, and an element. The
    closure returns the value that the accumulator should have for the next iteration.

    The initial value is the value the accumulator will have on the first call.

    After applying this closure to every element of the iterum, fold()
    returns the accumulator.

    Examples:

        >>> a = [1, 2, 3]
        >>> sum = iterum(a).fold(0, lambda acc, x: acc + x)
        >>> assert sum == 6

        Let's walk through each step of the iteration here:

        | element | acc | x | result |
        | ------- | --- | - | ------ |
        |         |  0  |   |        |
        |   1     |  0  | 1 |   1    |
        |   2     |  1  | 2 |   3    |
        |   3     |  3  | 3 |   6    |

        And so, our final result, 6.


    fold is left-associative:

        ```python
        >>> numbers = [1, 2, 3, 4, 5]
        >>> result = iterum(numbers).fold("0", lambda acc, x: f"({acc} + {x})")
        >>> assert result == "(((((0 + 1) + 2) + 3) + 4) + 5)"

        ```
    """
    acc = init
    for x in self:
        acc = f(acc, x)
    return acc

for_each(f: Callable[[T_co], object]) -> None

Calls a closure on each element of an iterum.

For loops are more idiomatic... but who cares!

Examples:

>>> v = []
>>> seq(5).map(lambda x: x * 2 + 1).for_each(v.append)
>>> assert v == [1, 3, 5, 7, 9]
Source code in iterum/_iterum.py
def for_each(self, f: Callable[[T_co], object], /) -> None:
    """
    Calls a closure on each element of an iterum.

    For loops are more idiomatic... but who cares!

    Examples:

        >>> v = []
        >>> seq(5).map(lambda x: x * 2 + 1).for_each(v.append)
        >>> assert v == [1, 3, 5, 7, 9]
    """
    for x in self:
        f(x)

fuse() -> Fuse[T_co]

Creates an iterum which ends after the first nil.

After an iterum returns nil, future calls may or may not yield Some(T) again. fuse() adapts an iterum, ensuring that after a nil is given, it will always return nil forever.

Examples:

>>> class Alternator(Iterator[int]):
...     def __init__(self) -> None:
...         self.i = 0
...     def __next__(self) -> int:
...         self.i += 1
...         if self.i % 5:
...             return self.i
...         else:
...             raise StopIteration()
>>> it = iterum(Alternator())
>>> assert list(it) == [1, 2, 3, 4]
>>> assert list(it) == [6, 7, 8, 9]
>>> assert list(it) == [11, 12, 13, 14]
>>> it = it.fuse()
>>> assert list(it) == [16, 17, 18, 19]
>>> assert list(it) == []
>>> assert list(it) == []
Source code in iterum/_iterum.py
def fuse(self) -> Fuse[T_co]:
    """
    Creates an iterum which ends after the first [nil][iterum.nil].

    After an iterum returns [nil][iterum.nil], future calls may or may not
    yield [Some(T)][iterum.Some] again. [fuse()][iterum.Iterum.fuse] adapts
    an iterum, ensuring that after a [nil][iterum.nil] is given, it will
    always return [nil][iterum.nil] forever.

    Examples:

        >>> class Alternator(Iterator[int]):
        ...     def __init__(self) -> None:
        ...         self.i = 0
        ...     def __next__(self) -> int:
        ...         self.i += 1
        ...         if self.i % 5:
        ...             return self.i
        ...         else:
        ...             raise StopIteration()

        >>> it = iterum(Alternator())
        >>> assert list(it) == [1, 2, 3, 4]
        >>> assert list(it) == [6, 7, 8, 9]
        >>> assert list(it) == [11, 12, 13, 14]

        >>> it = it.fuse()
        >>> assert list(it) == [16, 17, 18, 19]
        >>> assert list(it) == []
        >>> assert list(it) == []
    """
    return Fuse(self)

ge(other: Iterable[object] | Iterable[SupportsRichComparison]) -> bool

Determines if the elements of this Iterator are lexicographically greater than or equal to those of another.

Examples:

>>> assert iterum([1]).ge([1])
>>> assert not iterum([1]).ge([1, 2])
>>> assert iterum([1, 2]).ge([1])
>>> assert iterum([1, 2]).ge([1, 2])
Source code in iterum/_iterum.py
def ge(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> bool:
    """
    Determines if the elements of this Iterator are lexicographically
    greater than or equal to those of another.

    Examples:

        >>> assert iterum([1]).ge([1])
        >>> assert not iterum([1]).ge([1, 2])
        >>> assert iterum([1, 2]).ge([1])
        >>> assert iterum([1, 2]).ge([1, 2])
    """
    cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
    return cmp in (Ordering.Greater, Ordering.Equal)

gt(other: Iterable[object] | Iterable[SupportsRichComparison]) -> bool

Determines if the elements of this Iterator are lexicographically greater than those of another.

Examples:

>>> assert not iterum([1]).gt([1])
>>> assert not iterum([1]).gt([1, 2])
>>> assert iterum([1, 2]).gt([1])
>>> assert not iterum([1, 2]).gt([1, 2])
Source code in iterum/_iterum.py
def gt(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> bool:
    """
    Determines if the elements of this Iterator are lexicographically
    greater than those of another.

    Examples:

        >>> assert not iterum([1]).gt([1])
        >>> assert not iterum([1]).gt([1, 2])
        >>> assert iterum([1, 2]).gt([1])
        >>> assert not iterum([1, 2]).gt([1, 2])
    """
    cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
    return cmp == Ordering.Greater

inspect(f: Callable[[T_co], object]) -> Inspect[T_co]

Does something with each element of an iterum, passing the value on.

When using iterums, you’ll often chain several of them together. While working on such code, you might want to check out what’s happening at various parts in the pipeline. To do that, insert a call to inspect().

Examples:

>>> s = (
...    iterum([1, 4, 2, 3])
...    .inspect(lambda x: print(f"about to filter: {x}"))
...    .filter(lambda x: x % 2 == 0)
...    .inspect(lambda x: print(f"made it through filter: {x}"))
...    .fold(0, lambda sum, i: sum + i)
... )
...
about to filter: 1
about to filter: 4
made it through filter: 4
about to filter: 2
made it through filter: 2
about to filter: 3
>>> s
6
>>> a = [1, 2, 3]
>>> b = []
>>> c = (
...     iterum(a)
...     .map(lambda x: x * 2)
...     .inspect(b.append)
...     .take_while(lambda x: x < 5)
...     .collect(list)
... )
>>> assert b == [2, 4, 6]
>>> assert c == [2, 4]
Source code in iterum/_iterum.py
def inspect(self, f: Callable[[T_co], object], /) -> Inspect[T_co]:
    """
    Does something with each element of an iterum, passing the value on.

    When using iterums, you’ll often chain several of them together. While
    working on such code, you might want to check out what’s happening at
    various parts in the pipeline. To do that, insert a call to
    [inspect()][iterum.Iterum.inspect].

    Examples:

        >>> s = (
        ...    iterum([1, 4, 2, 3])
        ...    .inspect(lambda x: print(f"about to filter: {x}"))
        ...    .filter(lambda x: x % 2 == 0)
        ...    .inspect(lambda x: print(f"made it through filter: {x}"))
        ...    .fold(0, lambda sum, i: sum + i)
        ... )
        ...
        about to filter: 1
        about to filter: 4
        made it through filter: 4
        about to filter: 2
        made it through filter: 2
        about to filter: 3
        >>> s
        6

        >>> a = [1, 2, 3]
        >>> b = []
        >>> c = (
        ...     iterum(a)
        ...     .map(lambda x: x * 2)
        ...     .inspect(b.append)
        ...     .take_while(lambda x: x < 5)
        ...     .collect(list)
        ... )
        >>> assert b == [2, 4, 6]
        >>> assert c == [2, 4]
    """
    return Inspect(self, f)

last() -> Option[T_co]

Consumes the iterum, returning the last element.

This method will evaluate the iterum until it returns nil. While doing so, it keeps track of the current element. After nil is returned, last() will then return the last element it saw.

Examples:

>>> assert iterum([1, 2, 3]).last() == Some(3)
>>> assert iterum([1, 2, 3, 4, 5]).last() == Some(5)
Source code in iterum/_iterum.py
def last(self) -> Option[T_co]:
    """
    Consumes the iterum, returning the last element.

    This method will evaluate the iterum until it returns
    [nil][iterum.nil]. While doing so, it keeps track of the current
    element. After [nil][iterum.nil] is returned, last() will then return
    the last element it saw.

    Examples:

        >>> assert iterum([1, 2, 3]).last() == Some(3)
        >>> assert iterum([1, 2, 3, 4, 5]).last() == Some(5)
    """
    last = nil
    while (nxt := self.next()) is not nil:
        last = nxt

    return last

le(other: Iterable[object] | Iterable[SupportsRichComparison]) -> bool

Determines if the elements of this Iterator are lexicographically less or equal to those of another.

Examples:

>>> assert iterum([1]).le([1])
>>> assert iterum([1]).le([1, 2])
>>> assert not iterum([1, 2]).le([1])
>>> assert iterum([1, 2]).le([1, 2])
Source code in iterum/_iterum.py
def le(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> bool:
    """
    Determines if the elements of this Iterator are lexicographically less
    or equal to those of another.

    Examples:

        >>> assert iterum([1]).le([1])
        >>> assert iterum([1]).le([1, 2])
        >>> assert not iterum([1, 2]).le([1])
        >>> assert iterum([1, 2]).le([1, 2])
    """
    cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
    return cmp in (Ordering.Less, Ordering.Equal)

lt(other: Iterable[object] | Iterable[SupportsRichComparison]) -> bool

Determines if the elements of this Iterator are lexicographically less than those of another.

Examples:

>>> assert not iterum([1]).lt([1])
>>> assert iterum([1]).lt([1, 2])
>>> assert not iterum([1, 2]).lt([1])
>>> assert not iterum([1, 2]).lt([1, 2])
Source code in iterum/_iterum.py
def lt(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> bool:
    """
    Determines if the elements of this Iterator are lexicographically less
    than those of another.

    Examples:

        >>> assert not iterum([1]).lt([1])
        >>> assert iterum([1]).lt([1, 2])
        >>> assert not iterum([1, 2]).lt([1])
        >>> assert not iterum([1, 2]).lt([1, 2])
    """
    cmp = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
    return cmp == Ordering.Less

map(f: Callable[[T_co], U]) -> Map[U]

Takes a closure and creates an iterum which calls that closure on each element.

map() transforms one iterum into another, by means of its argument. It produces a new iterum which calls this closure on each element of the original iterum.

Examples:

>>> a = [1, 2, 3]
>>> itr = iterum(a).map(lambda x: x * 2)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == Some(4)
>>> assert itr.next() == Some(6)
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
def map(self, f: Callable[[T_co], U], /) -> Map[U]:
    """
    Takes a closure and creates an iterum which calls that closure on
    each element.

    [map()][iterum.Iterum.map] transforms one iterum into another, by
    means of its argument. It produces a new iterum which calls this
    closure on each element of the original iterum.

    Examples:

        >>> a = [1, 2, 3]
        >>> itr = iterum(a).map(lambda x: x * 2)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == Some(4)
        >>> assert itr.next() == Some(6)
        >>> assert itr.next() == nil
    """
    return Map(self, f)

map_while(predicate: Callable[[T_co], Option[U]]) -> MapWhile[U]

Creates an iterum that both yields elements based on a predicate and maps.

map_while() takes a closure as an argument. It will call this closure on each element of the iterum, and yield elements while it returns Some(_).

Examples:

>>> from functools import partial
>>> def checked_div(num: int, dem: int) -> Option[int]:
...    try:
...        return Some(num // dem)
...    except ZeroDivisionError:
...        return nil
...
>>> a = [-1, 4, 0, 1]
>>> it = iterum(a).map_while(partial(checked_div, 16))
>>> assert it.next() == Some(-16)
>>> assert it.next() == Some(4)
>>> assert it.next() == nil

Stops after first nil:

>>> a = [0, 1, 2, -3, 4, 5, -6]
>>> it = iterum(a).map_while(lambda x: Some(x) if x >= 0 else nil)
>>> vec = it.collect(list)
>>> assert vec == [0, 1, 2]
>>> assert it.next() == nil
Source code in iterum/_iterum.py
def map_while(self, predicate: Callable[[T_co], Option[U]], /) -> MapWhile[U]:
    """
    Creates an iterum that both yields elements based on a predicate and maps.

    [map_while()][iterum.Iterum.map_while] takes a closure as an argument.
    It will call this closure on each element of the iterum, and yield
    elements while it returns [Some(_)][iterum.Some].

    Examples:

        >>> from functools import partial
        >>> def checked_div(num: int, dem: int) -> Option[int]:
        ...    try:
        ...        return Some(num // dem)
        ...    except ZeroDivisionError:
        ...        return nil
        ...
        >>> a = [-1, 4, 0, 1]
        >>> it = iterum(a).map_while(partial(checked_div, 16))
        >>> assert it.next() == Some(-16)
        >>> assert it.next() == Some(4)
        >>> assert it.next() == nil


        Stops after first [nil][iterum.nil]:
        >>> a = [0, 1, 2, -3, 4, 5, -6]
        >>> it = iterum(a).map_while(lambda x: Some(x) if x >= 0 else nil)
        >>> vec = it.collect(list)
        >>> assert vec == [0, 1, 2]
        >>> assert it.next() == nil
    """
    return MapWhile(self, predicate)

max() -> Option[SupportsRichComparisonT]

Returns the maximum element of an iterum.

If several elements are equally maximum, the last element is returned. If the iterum is empty, nil is returned.

Examples:

>>> assert iterum([1, 2, 3]).max() == Some(3)
>>> assert iterum([]).max() == nil
Source code in iterum/_iterum.py
def max(
    self: Iterum[SupportsRichComparisonT],
) -> Option[SupportsRichComparisonT]:
    """
    Returns the maximum element of an iterum.

    If several elements are equally maximum, the last element is returned.
    If the iterum is empty, [nil][iterum.nil] is returned.

    Examples:

        >>> assert iterum([1, 2, 3]).max() == Some(3)
        >>> assert iterum([]).max() == nil
    """
    try:
        return Some(builtins.max(self))
    except ValueError:
        return nil

max_by(compare: Callable[[T_co, T_co], Ordering]) -> Option[T_co]

Returns the element that gives the maximum value with respect to the specified comparison function.

If several elements are equally maximum, the last element is returned. If the iterum is empty, nil is returned.

Examples:

>>> a = [-3, 0, 1, 5, -10]
>>> assert iterum(a).max_by(Ordering.cmp).unwrap() == 5
Source code in iterum/_iterum.py
def max_by(self, compare: Callable[[T_co, T_co], Ordering], /) -> Option[T_co]:
    """
    Returns the element that gives the maximum value with respect to the
    specified comparison function.

    If several elements are equally maximum, the last element is returned.
    If the iterum is empty, [nil][iterum.nil] is returned.

    Examples:

        >>> a = [-3, 0, 1, 5, -10]
        >>> assert iterum(a).max_by(Ordering.cmp).unwrap() == 5
    """
    max_ = self.next()
    if max_ is nil:
        return nil
    else:
        max_ = max_.unwrap()

    for nxt in self:
        if compare(max_, nxt) is Ordering.Less:
            max_ = nxt

    return Some(max_)

max_by_key(f: Callable[[T_co], SupportsRichComparison]) -> Option[T_co]

Returns the element that gives the maximum value from the specified function.

If several elements are equally maximum, the last element is returned. If the iterum is empty, nil is returned.

Examples:

>>> a = [-3, 0, 1, 5, -10]
>>> assert iterum(a).max_by_key(abs).unwrap() == -10
Source code in iterum/_iterum.py
def max_by_key(
    self, f: Callable[[T_co], SupportsRichComparison], /
) -> Option[T_co]:
    """
    Returns the element that gives the maximum value from the specified function.

    If several elements are equally maximum, the last element is returned.
    If the iterum is empty, [nil][iterum.nil] is returned.

    Examples:

        >>> a = [-3, 0, 1, 5, -10]
        >>> assert iterum(a).max_by_key(abs).unwrap() == -10
    """

    def compare(x, y) -> Ordering:
        fx = f(x)
        fy = f(y)
        return Ordering.cmp(fx, fy)

    return self.max_by(compare)

min() -> Option[SupportsRichComparisonT]

Returns the minimum element of an iterum.

If several elements are equally minimum, the first element is returned. If the iterum is empty, nil is returned.

Examples:

>>> assert iterum([1, 2, 3]).min() == Some(1)
>>> assert iterum([]).min() == nil
Source code in iterum/_iterum.py
def min(
    self: Iterum[SupportsRichComparisonT],
) -> Option[SupportsRichComparisonT]:
    """
    Returns the minimum element of an iterum.

    If several elements are equally minimum, the first element is returned.
    If the iterum is empty, [nil][iterum.nil] is returned.

    Examples:

        >>> assert iterum([1, 2, 3]).min() == Some(1)
        >>> assert iterum([]).min() == nil
    """
    try:
        return Some(builtins.min(self))
    except ValueError:
        return nil

min_by(compare: Callable[[T_co, T_co], Ordering]) -> Option[T_co]

Returns the element that gives the minimum value with respect to the specified comparison function.

If several elements are equally minimum, the first element is returned. If the iterum is empty, nil is returned.

Examples:

>>> a = [-3, 0, 1, 5, -10]
>>> assert iterum(a).min_by(Ordering.cmp).unwrap() == -10
Source code in iterum/_iterum.py
def min_by(self, compare: Callable[[T_co, T_co], Ordering], /) -> Option[T_co]:
    """
    Returns the element that gives the minimum value with respect to the
    specified comparison function.

    If several elements are equally minimum, the first element is returned.
    If the iterum is empty, [nil][iterum.nil] is returned.

    Examples:

        >>> a = [-3, 0, 1, 5, -10]
        >>> assert iterum(a).min_by(Ordering.cmp).unwrap() == -10
    """
    min_ = self.next()
    if min_ is nil:
        return nil
    else:
        min_ = min_.unwrap()

    for nxt in self:
        if compare(min_, nxt) is Ordering.Greater:
            min_ = nxt

    return Some(min_)

min_by_key(f: Callable[[T_co], SupportsRichComparison]) -> Option[T_co]

Returns the element that gives the minimum value from the specified function.

If several elements are equally minimum, the first element is returned. If the iterum is empty, nil is returned.

Examples:

>>> a = [-3, 0, 1, 5, -10]
>>> assert iterum(a).min_by_key(abs).unwrap() == 0
Source code in iterum/_iterum.py
def min_by_key(
    self, f: Callable[[T_co], SupportsRichComparison], /
) -> Option[T_co]:
    """
    Returns the element that gives the minimum value from the specified function.

    If several elements are equally minimum, the first element is returned.
    If the iterum is empty, [nil][iterum.nil] is returned.

    Examples:

        >>> a = [-3, 0, 1, 5, -10]
        >>> assert iterum(a).min_by_key(abs).unwrap() == 0
    """

    def compare(x, y) -> Ordering:
        fx = f(x)
        fy = f(y)
        return Ordering.cmp(fx, fy)

    return self.min_by(compare)

ne(other: Iterable[object] | Iterable[SupportsRichComparison]) -> bool

Determines if the elements of this Iterator are not equal to those of another.

Examples:

>>> assert not iterum([1]).ne([1])
>>> assert iterum([1]).ne([1, 2])
Source code in iterum/_iterum.py
def ne(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> bool:
    """
    Determines if the elements of this Iterator are not equal to those of another.

    Examples:

        >>> assert not iterum([1]).ne([1])
        >>> assert iterum([1]).ne([1, 2])
    """
    eq = self.eq(other)  # type: ignore | reason: ask for forgiveness not permission
    return not eq

nth(n: int) -> Option[T_co]

Returns the nth element of the iterum.

Like most indexing operations, the count starts from zero, so nth(0) returns the first value, nth(1) the second, and so on.

Note that all preceding elements, as well as the returned element, will be consumed from the iterum. That means that the preceding elements will be discarded, and also that calling nth(0) multiple times on the same iterum will return different elements.

nth() will return nil if n is greater than or equal to the length of the iterum.

Examples:

>>> a = [1, 2, 3]
>>> assert iterum(a).nth(1) == Some(2)

Calling nth multiple times doesn't rewind the iterum:

>>> itr = iterum([1, 2, 3])
>>> assert itr.nth(1) == Some(2)
>>> assert itr.nth(1) == nil

Returns nil if there are less than n + 1 elements:

>>> itr = iterum([1, 2, 3])
>>> assert itr.nth(3) == nil
Source code in iterum/_iterum.py
def nth(self, n: int, /) -> Option[T_co]:
    """
    Returns the nth element of the iterum.

    Like most indexing operations, the count starts from zero, so [nth(0)][iterum.Iterum.nth]
    returns the first value, [nth(1)][iterum.Iterum.nth] the second, and so on.

    Note that all preceding elements, as well as the returned element, will
    be consumed from the iterum. That means that the preceding elements
    will be discarded, and also that calling [nth(0)][iterum.Iterum.nth] multiple times on the
    same iterum will return different elements.

    [nth()][iterum.Iterum.nth] will return [nil][iterum.nil] if n is greater
    than or equal to the length of the iterum.

    Examples:

        >>> a = [1, 2, 3]
        >>> assert iterum(a).nth(1) == Some(2)

        Calling [nth][iterum.Iterum.nth] multiple times doesn't rewind the iterum:
        >>> itr = iterum([1, 2, 3])
        >>> assert itr.nth(1) == Some(2)
        >>> assert itr.nth(1) == nil

        Returns [nil][iterum.nil] if there are less than `n + 1` elements:
        >>> itr = iterum([1, 2, 3])
        >>> assert itr.nth(3) == nil
    """
    for i, x in enumerate(self):
        if i > n:
            return nil
        if i == n:
            return Some(x)
    return nil

partial_cmp(other: Iterable[object] | Iterable[SupportsRichComparison]) -> Option[Ordering]

Lexicographically compares the PartialOrd elements of this Iterator with those of another. The comparison works like short-circuit evaluation, returning a result without comparing the remaining elements. As soon as an order can be determined, the evaluation stops and a result is returned.

Examples:

>>> assert iterum([1]).partial_cmp([1]) == Some(Ordering.Equal)
>>> assert iterum([1, 2]).partial_cmp([1]) == Some(Ordering.Greater)
>>> assert iterum([1]).partial_cmp([1, 2]) == Some(Ordering.Less)

Results are determined by the order of evaluation:

>>> assert iterum([1, None]).partial_cmp([2, nil]) == Some(Ordering.Less)
>>> assert iterum([2, None]).partial_cmp([1, nil]) == Some(Ordering.Greater)
>>> assert iterum([None, 1]).partial_cmp([2, None]) == nil
Source code in iterum/_iterum.py
def partial_cmp(
    self: Iterum[SupportsRichComparison] | Iterum[object],
    other: Iterable[object] | Iterable[SupportsRichComparison],
    /,
) -> Option[Ordering]:
    """
    Lexicographically compares the PartialOrd elements of this Iterator with
    those of another. The comparison works like short-circuit evaluation,
    returning a result without comparing the remaining elements. As soon as
    an order can be determined, the evaluation stops and a result is returned.

    Examples:

        >>> assert iterum([1]).partial_cmp([1]) == Some(Ordering.Equal)
        >>> assert iterum([1, 2]).partial_cmp([1]) == Some(Ordering.Greater)
        >>> assert iterum([1]).partial_cmp([1, 2]) == Some(Ordering.Less)

        Results are determined by the order of evaluation:
        >>> assert iterum([1, None]).partial_cmp([2, nil]) == Some(Ordering.Less)
        >>> assert iterum([2, None]).partial_cmp([1, nil]) == Some(Ordering.Greater)
        >>> assert iterum([None, 1]).partial_cmp([2, None]) == nil
    """
    try:
        value = self.cmp(other)  # type: ignore | reason: ask for forgiveness not permission
    except TypeError:
        return nil
    else:
        return Some(value)

partition(f: Callable[[T_co], object], container: Callable[[Iterable[T_co]], U] = list) -> tuple[U, U]

Consumes an iterum, creating two collections from it.

The predicate passed to partition() can return True, or False. partition() returns a pair, all of the elements for which it returned True, and all of the elements for which it returned False.

Examples:

>>> a = [1, 2, 3]
>>> even, odd = iterum(a).partition(lambda n: n % 2 == 0)
>>> assert even == [2]
>>> assert odd == [1, 3]
Source code in iterum/_iterum.py
def partition(  # type: ignore
    self,
    f: Callable[[T_co], object],
    container: Callable[[Iterable[T_co]], U] = list,
    /,
) -> tuple[U, U]:
    """
    Consumes an iterum, creating two collections from it.

    The predicate passed to [partition()][iterum.Iterum.partition] can
    return `True`, or `False`. [partition()][iterum.Iterum.partition]
    returns a pair, all of the elements for which it returned `True`, and
    all of the elements for which it returned `False`.

    Examples:

        >>> a = [1, 2, 3]
        >>> even, odd = iterum(a).partition(lambda n: n % 2 == 0)
        >>> assert even == [2]
        >>> assert odd == [1, 3]
    """
    matches, notmatches = [], []
    for x in self:
        matches.append(x) if f(x) else notmatches.append(x)

    return container(matches), container(notmatches)

peekable() -> Peekable[T_co]

Creates an iterum which provides a peek attribute for viewing and setting the next element of the iterum without consuming it.

Examples:

>>> xs = [1, 2, 3]
>>> itr = iterum(xs).peekable()
>>> assert itr.peek == Some(1)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.peek == Some(3)
>>> assert itr.peek == Some(3)
>>> assert itr.next() == Some(3)
>>> assert itr.peek == nil
>>> assert itr.next() == nil
>>> xs = [1, 2, 3]
>>> itr = iterum(xs).peekable()
>>> assert itr.peek == Some(1)
>>> assert itr.peek == Some(1)
>>> assert itr.next() == Some(1)
>>> assert itr.peek == Some(2)
>>> itr.peek = 1000
>>> assert list(itr) == [1000, 3]
Source code in iterum/_iterum.py
def peekable(self) -> Peekable[T_co]:
    """
    Creates an iterum which provides a peek attribute for viewing
    and setting the next element of the iterum without consuming it.

    Examples:

        >>> xs = [1, 2, 3]
        >>> itr = iterum(xs).peekable()
        >>> assert itr.peek == Some(1)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.peek == Some(3)
        >>> assert itr.peek == Some(3)
        >>> assert itr.next() == Some(3)
        >>> assert itr.peek == nil
        >>> assert itr.next() == nil

        >>> xs = [1, 2, 3]
        >>> itr = iterum(xs).peekable()
        >>> assert itr.peek == Some(1)
        >>> assert itr.peek == Some(1)
        >>> assert itr.next() == Some(1)
        >>> assert itr.peek == Some(2)
        >>> itr.peek = 1000
        >>> assert list(itr) == [1000, 3]
    """
    return Peekable(self)

position(predicate: Callable[[T_co], object]) -> Option[int]

Searches for an element in an iterum, returning its index.

position() takes a closure that returns True or False. It applies this closure to each element of the iterum, and if one of them returns True, then position() returns Some(index). If all of them return False, it returns nil.

position() is short-circuiting; in other words, it will stop processing as soon as it finds a True.

Examples:

>>> a = [1, 2, 3]
>>> assert iterum(a).position(lambda x: x == 2) == Some(1)
>>> assert iterum(a).position(lambda x: x == 5) == nil
>>> it = iterum([1, 2, 3, 4])
>>> assert it.position(lambda x: x >= 2) == Some(1)
>>> assert it.next() == Some(3)
>>> assert it.position(lambda x: x == 4) == Some(0)
Source code in iterum/_iterum.py
def position(self, predicate: Callable[[T_co], object], /) -> Option[int]:
    """
    Searches for an element in an iterum, returning its index.

    [position()][iterum.Iterum.position] takes a closure that returns `True`
    or `False`. It applies this closure to each element of the iterum, and
    if one of them returns `True`, then [position()][iterum.Iterum.position]
    returns [Some(index)][iterum.Some]. If all of them return `False`, it
    returns [nil][iterum.nil].

    [position()][iterum.Iterum.position] is short-circuiting; in other
    words, it will stop processing as soon as it finds a `True`.

    Examples:

        >>> a = [1, 2, 3]
        >>> assert iterum(a).position(lambda x: x == 2) == Some(1)
        >>> assert iterum(a).position(lambda x: x == 5) == nil


        >>> it = iterum([1, 2, 3, 4])
        >>> assert it.position(lambda x: x >= 2) == Some(1)
        >>> assert it.next() == Some(3)
        >>> assert it.position(lambda x: x == 4) == Some(0)
    """
    for i, x in enumerate(self):
        if predicate(x):
            return Some(i)
    return nil

product() -> Option[SupportsMulT]

Iterates over the entire iterum, multiplying all the elements

An empty iterum returns nil.

Examples:

>>> def factorial(n: int) -> int:
...     return seq(1, n + 1).product().unwrap_or(1)
...
>>> assert factorial(0) == 1
>>> assert factorial(1) == 1
>>> assert factorial(5) == 120
Source code in iterum/_iterum.py
def product(self: Iterum[SupportsMulT]) -> Option[SupportsMulT]:
    """
    Iterates over the entire iterum, multiplying all the elements

    An empty iterum returns [nil][iterum.nil].

    Examples:

        >>> def factorial(n: int) -> int:
        ...     return seq(1, n + 1).product().unwrap_or(1)
        ...
        >>> assert factorial(0) == 1
        >>> assert factorial(1) == 1
        >>> assert factorial(5) == 120
    """
    return self.reduce(lambda acc, x: acc * x)

reduce(f: Callable[[T_co, T_co], T_co]) -> Option[T_co]

Reduces the elements to a single one, by repeatedly applying a reducing operation.

If the iterum is empty, returns nil; otherwise, returns the result of the reduction.

The reducing function is a closure with two arguments: an ‘accumulator’, and an element. For iterums with at least one element, this is the same as fold() with the first element of the iterum as the initial accumulator value, folding every subsequent element into it.

Examples:

>>> reduced = seq(1, 10).reduce(lambda acc, e: acc + e).unwrap()
>>> assert reduced == 45
Source code in iterum/_iterum.py
def reduce(self, f: Callable[[T_co, T_co], T_co], /) -> Option[T_co]:
    """
    Reduces the elements to a single one, by repeatedly applying a reducing operation.

    If the iterum is empty, returns [nil][iterum.nil]; otherwise, returns
    the result of the reduction.

    The reducing function is a closure with two arguments: an ‘accumulator’,
    and an element. For iterums with at least one element, this is the
    same as [fold()][iterum.Iterum.fold] with the first element of the
    iterum as the initial accumulator value, folding every subsequent
    element into it.

    Examples:

        >>> reduced = seq(1, 10).reduce(lambda acc, e: acc + e).unwrap()
        >>> assert reduced == 45
    """
    first = self.next()
    if first is nil:
        return nil
    else:
        return Some(self.fold(first.unwrap(), f))

scan(init: U, f: Callable[[State[U], T_co], Option[V]]) -> Scan[V]

An iterum adapter which, like fold, holds internal state, but unlike fold, produces a new iterum.

scan() takes two arguments: an initial value which seeds the internal state, and a closure with two arguments, the first being the internal state and the second an iterum element. The closure can assign to the internal state to share state between iterations.

Examples:

>>> itr = iterum([1, 2, 3, 4])
>>> def scanner(state: State, x: int) -> Option[int]:
...     state.value *= x
...     if state.value > 6:
...         return nil
...     return Some(-state.value)
...
>>> scan = itr.scan(1, scanner)
>>> assert scan.next() == Some(-1)
>>> assert scan.next() == Some(-2)
>>> assert scan.next() == Some(-6)
>>> assert scan.next() == nil
Source code in iterum/_iterum.py
def scan(self, init: U, f: Callable[[State[U], T_co], Option[V]], /) -> Scan[V]:
    """
    An iterum adapter which, like fold, holds internal state, but unlike
    fold, produces a new iterum.

    [scan()][iterum.Iterum.scan] takes two arguments: an initial value which
    seeds the internal state, and a closure with two arguments, the first
    being the internal state and the second an iterum element.
    The closure can assign to the internal state to share state between iterations.

    Examples:

        >>> itr = iterum([1, 2, 3, 4])
        >>> def scanner(state: State, x: int) -> Option[int]:
        ...     state.value *= x
        ...     if state.value > 6:
        ...         return nil
        ...     return Some(-state.value)
        ...
        >>> scan = itr.scan(1, scanner)
        >>> assert scan.next() == Some(-1)
        >>> assert scan.next() == Some(-2)
        >>> assert scan.next() == Some(-6)
        >>> assert scan.next() == nil
    """
    return Scan(self, init, f)

skip(n: int) -> Skip[T_co]

Creates an iterum that skips the first n elements.

skip(n) skips elements until n elements are skipped or the end of the iterum is reached (whichever happens first). After that, all the remaining elements are yielded. In particular, if the original iterum is too short, then the returned iterum is empty.

Examples:

>>> itr = iterum([1, 2, 3]).skip(2)
>>> assert itr.next() == Some(3)
>>> assert itr.next() == nil

Skipping past end:

>>> itr = iterum([1, 2, 3]).skip(10)
>>> assert itr.next() == nil
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
def skip(self, n: int, /) -> Skip[T_co]:
    """
    Creates an iterum that skips the first n elements.

    [skip(n)][iterum.Iterum.skip] skips elements until n elements are
    skipped or the end of the iterum is reached (whichever happens first).
    After that, all the remaining elements are yielded. In particular, if
    the original iterum is too short, then the returned iterum is empty.

    Examples:

        >>> itr = iterum([1, 2, 3]).skip(2)
        >>> assert itr.next() == Some(3)
        >>> assert itr.next() == nil

        Skipping past end:
        >>> itr = iterum([1, 2, 3]).skip(10)
        >>> assert itr.next() == nil
        >>> assert itr.next() == nil
    """
    return Skip(self, n)

skip_while(predicate: Callable[[T_co], object]) -> SkipWhile[T_co]

Creates an iterum that skips elements based on a predicate.

skip_while() takes a closure as an argument. It will call this closure on each element of the iterum, and ignore elements until it returns False.

After False is returned, skip_while()’s job is over, and the rest of the elements are yielded.

Examples:

>>> itr = iterum([-1, 0, 1]).skip_while(lambda x: x < 0)
>>> assert itr.next() == Some(0)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == nil

After first False condition is hit, no further elements are checked:

>>> itr = iterum([-1, 0, 1, -3]).skip_while(lambda x: x < 0)
>>> assert itr.next() == Some(0)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(-3)
Source code in iterum/_iterum.py
def skip_while(self, predicate: Callable[[T_co], object], /) -> SkipWhile[T_co]:
    """
    Creates an iterum that skips elements based on a predicate.

    [skip_while()][iterum.Iterum.skip_while] takes a closure as an argument.
    It will call this closure on each element of the iterum, and ignore
    elements until it returns `False`.

    After `False` is returned, [skip_while()][iterum.Iterum.skip_while]’s
    job is over, and the rest of the elements are yielded.

    Examples:

        >>> itr = iterum([-1, 0, 1]).skip_while(lambda x: x < 0)
        >>> assert itr.next() == Some(0)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == nil

        After first `False` condition is hit, no further elements are checked:
        >>> itr = iterum([-1, 0, 1, -3]).skip_while(lambda x: x < 0)
        >>> assert itr.next() == Some(0)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(-3)
    """
    return SkipWhile(self, predicate)

step_by(step: int) -> StepBy[T_co]

Creates an iterum starting at the same point, but stepping by the given amount at each iteration. This always includes the first element.

Examples:

>>> itr = iterum([0, 1, 2, 3, 4, 5]).step_by(2)
>>> assert itr.next() == Some(0)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == Some(4)
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
def step_by(self, step: int, /) -> StepBy[T_co]:
    """
    Creates an iterum starting at the same point, but stepping by the
    given amount at each iteration. This always includes the first element.

    Examples:

        >>> itr = iterum([0, 1, 2, 3, 4, 5]).step_by(2)
        >>> assert itr.next() == Some(0)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == Some(4)
        >>> assert itr.next() == nil
    """
    return StepBy(self, step)

sum() -> Option[SupportsSumNoDefaultT]

Sums the elements of an iterum.

Takes each element, adds them together, and returns the result.

An empty iterum returns nil.

Examples:

>>> a = [1, 2, 3]
>>> sum_ = iterum(a).sum().unwrap_or(0)
>>> assert sum_ == 6
>>> sum_ = iterum([]).sum().unwrap_or(0)
>>> assert sum_ == 0
Source code in iterum/_iterum.py
def sum(self: Iterum[SupportsSumNoDefaultT]) -> Option[SupportsSumNoDefaultT]:
    """
    Sums the elements of an iterum.

    Takes each element, adds them together, and returns the result.

    An empty iterum returns [nil][iterum.nil].

    Examples:

        >>> a = [1, 2, 3]
        >>> sum_ = iterum(a).sum().unwrap_or(0)
        >>> assert sum_ == 6

        >>> sum_ = iterum([]).sum().unwrap_or(0)
        >>> assert sum_ == 0
    """
    # NOTE: This forces users to pick a default or suffer the unwrapping consequences
    # a more reasonable interface since an implicit default isn't a thing
    first = self.next()
    if first is nil:
        return nil

    return Some(sum(self, start=first.unwrap()))

take(n: int) -> Take[T_co]

Creates an iterum that yields the first n elements, or fewer if the underlying iterum ends sooner.

take(n) yields elements until n elements are yielded or the end of the iterum is reached (whichever happens first). The returned iterum is a prefix of length n if the original iterum contains at least n elements, otherwise it contains all of the (fewer than n) elements of the original iterum.

Examples:

>>> a = [1, 2, 3]
>>> itr = iterum(a).take(2)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == nil
>>> a = [1, 2, 3]
>>> itr = iterum(a).take(2)
>>> assert list(itr) == [1, 2]
>>> assert itr.next() == nil

Truncate an infinite iterum:

>>> itr = seq(...).take(3)
>>> assert itr.next() == Some(0)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == nil

Taking more than you have:

>>> itr = iterum([1, 2]).take(5)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
def take(self, n: int, /) -> Take[T_co]:
    """
    Creates an iterum that yields the first n elements, or fewer if the
    underlying iterum ends sooner.

    [take(n)][iterum.Iterum.take] yields elements until n elements are
    yielded or the end of the iterum is reached (whichever happens first).
    The returned iterum is a prefix of length n if the original iterum
    contains at least n elements, otherwise it contains all of the (fewer
    than n) elements of the original iterum.

    Examples:

        >>> a = [1, 2, 3]
        >>> itr = iterum(a).take(2)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == nil


        >>> a = [1, 2, 3]
        >>> itr = iterum(a).take(2)
        >>> assert list(itr) == [1, 2]
        >>> assert itr.next() == nil


        Truncate an infinite iterum:
        >>> itr = seq(...).take(3)
        >>> assert itr.next() == Some(0)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == nil

        Taking more than you have:
        >>> itr = iterum([1, 2]).take(5)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == nil
    """
    return Take(self, n)

take_while(predicate: Callable[[T_co], object]) -> TakeWhile[T_co]

Creates an iterum that yields elements based on a predicate.

take_while() takes a closure as an argument. It will call this closure on each element of the iterum, and yield elements while it returns True.

After False is returned, take_while()’s job is over, and the rest of the elements are ignored.

Examples:

>>> a = [-1, 0, 1]
>>> itr = iterum(a).take_while(lambda x: x < 0)
>>> assert itr.next() == Some(-1)
>>> assert itr.next() == nil

Stop after first False:

>>> a = [-1, 0, 1, -2]
>>> itr = iterum(a).take_while(lambda x: x < 0)
>>> assert itr.next() == Some(-1)
>>> assert itr.next() == nil
Source code in iterum/_iterum.py
def take_while(self, predicate: Callable[[T_co], object], /) -> TakeWhile[T_co]:
    """
    Creates an iterum that yields elements based on a predicate.

    [take_while()][iterum.Iterum.take_while] takes a closure as an argument.
    It will call this closure on each element of the iterum, and yield
    elements while it returns `True`.

    After `False` is returned, [take_while()][iterum.Iterum.take_while]’s
    job is over, and the rest of the elements are ignored.

    Examples:

        >>> a = [-1, 0, 1]
        >>> itr = iterum(a).take_while(lambda x: x < 0)
        >>> assert itr.next() == Some(-1)
        >>> assert itr.next() == nil

        Stop after first `False`:
        >>> a = [-1, 0, 1, -2]
        >>> itr = iterum(a).take_while(lambda x: x < 0)
        >>> assert itr.next() == Some(-1)
        >>> assert itr.next() == nil
    """
    return TakeWhile(self, predicate)

try_fold(init: U, f: Callable[[U, T_co], U], /, *, exception: type[BaseException] | tuple[type[BaseException], ...] = Exception) -> Option[U]

An iterum method that applies a function as long as it returns successfully, producing a single, final value.

try_fold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and an element. The closure either returns successfully, with the value that the accumulator should have for the next iteration, or it raises an exception which short-circuits the iteration.

Examples:

>>> def checked_add_i8(lhs: int, rhs: int) -> int:
...     value = lhs + rhs
...     if -128 <= value <= 127:
...         return value
...     else:
...         raise ValueError("Overflow!")
...
>>> a = [1, 2, 3]
>>> sum = iterum(a).try_fold(0, checked_add_i8)
>>> assert sum == Some(6)

short-circuit after a failure:

>>> it = iterum([10, 20, 30, 100, 40, 50])
>>> sum = it.try_fold(0, checked_add_i8)
>>> assert sum == nil
>>> assert list(it) == [40, 50]
Source code in iterum/_iterum.py
def try_fold(
    self,
    init: U,
    f: Callable[[U, T_co], U],
    /,
    *,
    exception: type[BaseException] | tuple[type[BaseException], ...] = Exception,
) -> Option[U]:
    """
    An iterum method that applies a function as long as it returns
    successfully, producing a single, final value.

    [try_fold()][iterum.Iterum.try_fold] takes two arguments: an initial
    value, and a closure with two arguments: an ‘accumulator’, and an
    element. The closure either returns successfully, with the value that
    the accumulator should have for the next iteration, or it raises an
    exception which short-circuits the iteration.

    Examples:

        >>> def checked_add_i8(lhs: int, rhs: int) -> int:
        ...     value = lhs + rhs
        ...     if -128 <= value <= 127:
        ...         return value
        ...     else:
        ...         raise ValueError("Overflow!")
        ...
        >>> a = [1, 2, 3]
        >>> sum = iterum(a).try_fold(0, checked_add_i8)
        >>> assert sum == Some(6)

        short-circuit after a failure:
        >>> it = iterum([10, 20, 30, 100, 40, 50])
        >>> sum = it.try_fold(0, checked_add_i8)
        >>> assert sum == nil
        >>> assert list(it) == [40, 50]
    """
    acc = init
    for x in self:
        try:
            acc = f(acc, x)
        except exception:
            return nil

    return Some(acc)

unzip(container: Callable[[Iterable[object]], U] = list) -> tuple[U, U]

Converts an iterum of pairs into a pair of containers.

unzip() consumes an entire iterum of pairs, producing two collections: one from the left elements of the pairs, and one from the right elements.

This function is, in some sense, the opposite of zip.

Examples:

>>> a = [(1, 2), (3, 4), (5, 6)]
>>> left, right = iterum(a).unzip()
>>> assert left == [1, 3, 5]
>>> assert right == [2, 4, 6]
Source code in iterum/_iterum.py
def unzip(
    self: Iterum[tuple[object, object]],
    container: Callable[[Iterable[object]], U] = list,
    /,
) -> tuple[U, U]:
    """
    Converts an iterum of pairs into a pair of containers.

    [unzip()][iterum.Iterum.unzip] consumes an entire iterum of pairs,
    producing two collections: one from the left elements of the pairs, and
    one from the right elements.

    This function is, in some sense, the opposite of [zip][iterum.Iterum.zip].

    Examples:

        >>> a = [(1, 2), (3, 4), (5, 6)]
        >>> left, right = iterum(a).unzip()
        >>> assert left == [1, 3, 5]
        >>> assert right == [2, 4, 6]
    """
    left, right = map(container, zip(*self))
    return left, right

zip(other: Iterable[U]) -> Zip[T_co, U]

‘Zips up’ two iterables into a single iterum of pairs.

zip() returns a new iterum that will iterate over two other iterables, returning a tuple where the first element comes from the first iterable, and the second element comes from the second iterable.

If either iterable returns nil, next from the zipped iterum will return nil. If the zipped iterum has no more elements to return then each further attempt to advance it will first try to advance the first iterable at most one time and if it still yielded an item try to advance the second iterable at most one time.

To ‘undo’ the result of zipping up two iterables, see unzip.

Examples:

>>> a1 = [1, 2, 3]
>>> a2 = [4, 5, 6]
>>> itr = iterum(a1).zip(a2)
>>> assert itr.next() == Some((1, 4))
>>> assert itr.next() == Some((2, 5))
>>> assert itr.next() == Some((3, 6))
>>> assert itr.next() == nil

zip smaller with larger:

>>> inf_itr = seq(...)
>>> foo_itr = iterum("foo")
>>> zip_itr = foo_itr.zip(inf_itr)
>>> assert zip_itr.next() == Some(("f", 0))
>>> assert zip_itr.next() == Some(("o", 1))
>>> assert zip_itr.next() == Some(("o", 2))
>>> assert zip_itr.next() == nil
>>> assert foo_itr.next() == nil
>>> assert inf_itr.next() == Some(3)

zip larger with smaller:

>>> inf_itr = seq(...)
>>> foo_itr = iterum("foo")
>>> zip_itr = inf_itr.zip(foo_itr)
>>> assert zip_itr.next() == Some((0, "f"))
>>> assert zip_itr.next() == Some((1, "o"))
>>> assert zip_itr.next() == Some((2, "o"))
>>> assert zip_itr.next() == nil
>>> assert foo_itr.next() == nil
>>> assert inf_itr.next() == Some(4)
Source code in iterum/_iterum.py
def zip(self, other: Iterable[U], /) -> Zip[T_co, U]:
    """
    ‘Zips up’ two iterables into a single iterum of pairs.

    [zip()][iterum.Iterum.zip] returns a new iterum that will iterate over
    two other iterables, returning a tuple where the first element comes
    from the first iterable, and the second element comes from the second iterable.

    If either iterable returns [nil][iterum.nil], next from the zipped
    iterum will return [nil][iterum.nil]. If the zipped iterum has no
    more elements to return then each further attempt to advance it will
    first try to advance the first iterable at most one time and if it still
    yielded an item try to advance the second iterable at most one time.

    To ‘undo’ the result of zipping up two iterables, see [unzip][iterum.Iterum.unzip].

    Examples:

        >>> a1 = [1, 2, 3]
        >>> a2 = [4, 5, 6]
        >>> itr = iterum(a1).zip(a2)
        >>> assert itr.next() == Some((1, 4))
        >>> assert itr.next() == Some((2, 5))
        >>> assert itr.next() == Some((3, 6))
        >>> assert itr.next() == nil

        zip smaller with larger:
        >>> inf_itr = seq(...)
        >>> foo_itr = iterum("foo")
        >>> zip_itr = foo_itr.zip(inf_itr)
        >>> assert zip_itr.next() == Some(("f", 0))
        >>> assert zip_itr.next() == Some(("o", 1))
        >>> assert zip_itr.next() == Some(("o", 2))
        >>> assert zip_itr.next() == nil
        >>> assert foo_itr.next() == nil
        >>> assert inf_itr.next() == Some(3)

        zip larger with smaller:
        >>> inf_itr = seq(...)
        >>> foo_itr = iterum("foo")
        >>> zip_itr = inf_itr.zip(foo_itr)
        >>> assert zip_itr.next() == Some((0, "f"))
        >>> assert zip_itr.next() == Some((1, "o"))
        >>> assert zip_itr.next() == Some((2, "o"))
        >>> assert zip_itr.next() == nil
        >>> assert foo_itr.next() == nil
        >>> assert inf_itr.next() == Some(4)
    """
    return Zip(self, other)

iterum.diterum

Bases: Diterum[T_co]

Implements a Diterum interface from a sequence.

Examples:

>>> itr = diterum([1, 2, 3])
>>> assert itr.next() == Some(1)
>>> assert itr.next_back() == Some(3)
>>> assert itr.next() == Some(2)
>>> assert itr.next_back() == nil
>>> assert itr.next() == nil
>>> itr = diterum([1, 2, 3])
>>> assert itr.rfold(0, lambda acc, x: acc*2 + x) == 17
>>> x = [0, 1, 2, 3, 4]
>>> y = (
...     diterum(x)
...     .rev()
...     .map(lambda x: x**2 + 1)
...     .filter(lambda x: x % 2)
...     .collect()
... )
>>> assert y == [17, 5, 1]
Source code in iterum/_diterum.py
class diterum(Diterum[T_co]):
    """
    Implements a [Diterum][iterum.Diterum] interface from a sequence.

    Examples:

        >>> itr = diterum([1, 2, 3])
        >>> assert itr.next() == Some(1)
        >>> assert itr.next_back() == Some(3)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next_back() == nil
        >>> assert itr.next() == nil

        >>> itr = diterum([1, 2, 3])
        >>> assert itr.rfold(0, lambda acc, x: acc*2 + x) == 17

        >>> x = [0, 1, 2, 3, 4]
        >>> y = (
        ...     diterum(x)
        ...     .rev()
        ...     .map(lambda x: x**2 + 1)
        ...     .filter(lambda x: x % 2)
        ...     .collect()
        ... )
        >>> assert y == [17, 5, 1]
    """

    __slots__ = ("_seq", "_front", "_back")

    def __init__(self, __seq: Sequence[T_co], /) -> None:
        self._seq = __seq
        self._front = 0
        self._back = len(__seq) - 1

    def next(self) -> Option[T_co]:
        """
        Returns the next value in the sequence from the front if present,
        otherwise [nil][iterum.nil].

        Examples:

            >>> itr = diterum([1, 2])
            >>> assert itr.next() == Some(1)
            >>> assert itr.next() == Some(2)
            >>> assert itr.next() == nil
        """

        if self._back < self._front:
            return nil

        nxt = self._seq[self._front]
        self._front += 1
        return Some(nxt)

    def next_back(self) -> Option[T_co]:
        """
        Returns the next value in the sequence from the back if present,
        otherwise [nil][iterum.nil].

        Examples:

            >>> itr = diterum([1, 2])
            >>> assert itr.next_back() == Some(2)
            >>> assert itr.next_back() == Some(1)
            >>> assert itr.next_back() == nil
        """

        if self._back < self._front:
            return nil

        nxt = self._seq[self._back]
        self._back -= 1
        return Some(nxt)

    def len(self) -> int:
        """
        Returns the remaining length of the sequence.

        Examples:

            >>> itr = diterum([1, 2])
            >>> assert itr.len() == 2
            >>> assert itr.next() == Some(1)
            >>> assert itr.len() == 1
            >>> assert itr.next_back() == Some(2)
            >>> assert itr.len() == 0
            >>> assert itr.next() == nil
            >>> assert itr.len() == 0
        """

        if self._back < self._front:
            return 0

        return self._back + 1 - self._front

next() -> Option[T_co]

Returns the next value in the sequence from the front if present, otherwise nil.

Examples:

>>> itr = diterum([1, 2])
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == nil
Source code in iterum/_diterum.py
def next(self) -> Option[T_co]:
    """
    Returns the next value in the sequence from the front if present,
    otherwise [nil][iterum.nil].

    Examples:

        >>> itr = diterum([1, 2])
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == nil
    """

    if self._back < self._front:
        return nil

    nxt = self._seq[self._front]
    self._front += 1
    return Some(nxt)

next_back() -> Option[T_co]

Returns the next value in the sequence from the back if present, otherwise nil.

Examples:

>>> itr = diterum([1, 2])
>>> assert itr.next_back() == Some(2)
>>> assert itr.next_back() == Some(1)
>>> assert itr.next_back() == nil
Source code in iterum/_diterum.py
def next_back(self) -> Option[T_co]:
    """
    Returns the next value in the sequence from the back if present,
    otherwise [nil][iterum.nil].

    Examples:

        >>> itr = diterum([1, 2])
        >>> assert itr.next_back() == Some(2)
        >>> assert itr.next_back() == Some(1)
        >>> assert itr.next_back() == nil
    """

    if self._back < self._front:
        return nil

    nxt = self._seq[self._back]
    self._back -= 1
    return Some(nxt)

len() -> int

Returns the remaining length of the sequence.

Examples:

>>> itr = diterum([1, 2])
>>> assert itr.len() == 2
>>> assert itr.next() == Some(1)
>>> assert itr.len() == 1
>>> assert itr.next_back() == Some(2)
>>> assert itr.len() == 0
>>> assert itr.next() == nil
>>> assert itr.len() == 0
Source code in iterum/_diterum.py
def len(self) -> int:
    """
    Returns the remaining length of the sequence.

    Examples:

        >>> itr = diterum([1, 2])
        >>> assert itr.len() == 2
        >>> assert itr.next() == Some(1)
        >>> assert itr.len() == 1
        >>> assert itr.next_back() == Some(2)
        >>> assert itr.len() == 0
        >>> assert itr.next() == nil
        >>> assert itr.len() == 0
    """

    if self._back < self._front:
        return 0

    return self._back + 1 - self._front

iterum.Diterum

Bases: Iterum[T_co]

Iterator-like abstract base class that is reversible and of known size. To implement this, inherit from Diterum and then define a next, next_back, and len method. See diterum for an example.

Source code in iterum/_diterum.py
class Diterum(Iterum[T_co]):
    """
    Iterator-like abstract base class that is reversible and of known size.
    To implement this, inherit from [Diterum][iterum.Diterum] and then define
    a [next][iterum.Iterum.next], [next_back][iterum.Diterum.next_back], and
    [len][iterum.Diterum.len] method. See [diterum][iterum.diterum] for an
    example.
    """

    __slots__ = ()

    @abstractmethod
    def next_back(self) -> Option[T_co]:
        """
        Required method.

        Removes and returns an element from the end of the diterum.

        Returns [nil][iterum.nil] when there are no more elements.

        Examples:

            >>> di = diterum([1, 2, 3, 4, 5, 6])
            >>> assert di.next() == Some(1)
            >>> assert di.next_back() == Some(6)
            >>> assert di.next_back() == Some(5)
            >>> assert di.next() == Some(2)
            >>> assert di.next() == Some(3)
            >>> assert di.next() == Some(4)
            >>> assert di.next() == nil
            >>> assert di.next_back() == nil
        """
        ...

    @abstractmethod
    def len(self) -> int:
        """
        Required method.

        Returns the exact remaining length of the diterum.

        Examples:

            >>> di = diterum([1, 2, 3, 4])
            >>> assert di.len() == 4
            >>> assert di.next() == Some(1)
            >>> assert di.len() == 3
            >>> assert di.next_back() == Some(4)
            >>> assert di.len() == 2
            >>> assert di.collect() == [2, 3]
            >>> assert di.next() == nil
            >>> assert di.len() == 0
        """
        ...

    # Defined by Iterator
    def rev(self) -> Rev[T_co]:
        """
        Reverses an diterum’s direction.

        Usually, iterums iterate from left to right. After using
        [rev()][iterum.Diterum.rev], an iterum will instead iterate from
        right to left.

        Examples:

            >>> di = diterum([1, 2, 3]).rev()
            >>> assert di.next() == Some(3)
            >>> assert di.next() == Some(2)
            >>> assert di.next() == Some(1)
            >>> assert di.next() == nil
        """
        return Rev(self)

    def rposition(self, predicate: Callable[[T_co], object], /) -> Option[int]:
        """
        Searches for an element in a diterum from the right, returning its index.

        [rposition()][iterum.Diterum.rposition] takes a closure that returns
        `True` or `False`. It applies this closure to each element of the
        diterum, starting from the end, and if one of them returns `True`, then
        [rposition()][iterum.Diterum.rposition] returns [Some(index)][iterum.Some].
        If all of them return `False`, it returns [nil][iterum.nil].

        [rposition()][iterum.Diterum.rposition] is short-circuiting; in other
        words, it will stop processing as soon as it finds a `True`.

        Examples:

            >>> di = diterum([1, 2, 3])
            >>> assert di.rposition(lambda x: x == 3) == Some(2)
            >>> assert di.rposition(lambda x: x == 5) == nil

            Short-circuiting after first `True`:
            >>> di = diterum([-1, 2, 3, 4])
            >>> assert di.rposition(lambda x: x >= 2) == Some(3)
            >>> assert di.next() == Some(-1)
        """
        len = self.len()
        return self.rev().position(predicate).map(lambda x: len - x - 1)

    # Defined by DoubleEndedIterator
    def nth_back(self, n: int, /) -> Option[T_co]:
        """
        Returns the nth element from the end of the diterum.

        This is essentially the reversed version of [Iterum.nth()][iterum.Iterum.nth].
        Although like most indexing operations, the count starts from zero, so
        [nth_back(0)][iterum.Diterum.nth_back] returns the first value from the end,
        [nth_back(1)][iterum.Diterum.nth_back] the second, and so on.

        Note that all elements between the end and the returned element will be
        consumed, including the returned element. This also means that calling
        [nth_back(0)][iterum.Diterum.nth_back] multiple times on the same diterum
        will return different elements.

        [nth_back()][iterum.Diterum.nth_back] will return [nil][iterum.nil] if n
        is greater than or equal to the length of the diterum.

        Examples:

            >>> di = diterum([1, 2, 3])
            >>> assert di.nth_back(2) == Some(1)

            Does not rewind:
            >>> di = diterum([1, 2, 3])
            >>> assert di.nth_back(1) == Some(2)
            >>> assert di.nth_back(1) == nil

            Returns [nil][iterum.nil] if there are less than `n + 1` elements:
            >>> di = diterum([1, 2, 3])
            >>> assert di.nth_back(10) == nil
        """
        return self.rev().nth(n)

    def rfind(self, predicate: Callable[[T_co], object], /) -> Option[T_co]:
        """
        Searches for an element of a diterum from the back that satisfies a predicate.

        [rfind()][iterum.Diterum.rfind] takes a closure that returns `True` or
        `False`. It applies this closure to each element of the diterum,
        starting at the end, and if any of them return `True`, then
        [rfind()][iterum.Diterum.rfind] returns [Some(element)][iterum.Some]. If
        they all return `False`, it returns [nil][iterum.nil].

        [rfind()][iterum.Diterum.rfind] is short-circuiting; in other words, it
        will stop processing as soon as the closure returns `True`.

        Examples:

            >>> di = diterum([1, 2, 3])
            >>> assert di.rfind(lambda x: x == 2) == Some(2)
            >>> assert di.rfind(lambda x: x == 5) == nil

            Stops at first `True`:
            >>> di = diterum([1, 2, 3])
            >>> assert di.rfind(lambda x: x == 2) == Some(2)
            >>> assert di.next_back() == Some(1)
        """
        return self.rev().find(predicate)

    def rfold(self, init: U, f: Callable[[U, T_co], U], /) -> U:
        """
        A diterum method that reduces the diterum’s elements to a single,
        final value, starting from the back.

        This is the reverse version of [Iterum.fold()][iterum.Iterum.fold]:
        it takes elements starting from the back of the diterum.

        [rfold()][iterum.Diterum.rfold] takes two arguments: an initial value,
        and a closure with two arguments: an ‘accumulator’, and an element. The
        closure returns the value that the accumulator should have for the next
        iteration.

        The initial value is the value the accumulator will have on the first call.

        After applying this closure to every element of the diterum,
        [rfold()][iterum.Diterum.rfold] returns the accumulator.

        Examples:

            >>> di = diterum([1, 2, 3])
            >>> sum = di.rfold(0, lambda acc, x: acc + x)
            >>> assert sum == 6

        rfold is right-associtive:

            ```python
            >>> numbers = [1, 2, 3, 4, 5]
            >>> zero = "0"
            >>> result = diterum(numbers).rfold(zero, lambda acc, x: f"({x} + {acc})")
            >>> assert result == "(1 + (2 + (3 + (4 + (5 + 0)))))"

            ```
        """
        return self.rev().fold(init, f)

    def try_rfold(
        self,
        init: U,
        f: Callable[[U, T_co], U],
        /,
        *,
        exception: type[BaseException] | tuple[type[BaseException], ...] = Exception,
    ) -> Option[U]:
        """
        This is the reverse version of [Iterum.try_fold()][iterum.Iterum.try_fold]:
        it takes elements starting from the back of the diterum.

        Examples:

            >>> di = diterum(["1", "2", "3"])
            >>> sum = di.try_rfold(0, lambda acc, x: acc + int(x), exception=TypeError)
            >>> assert sum == Some(6)
        """
        return self.rev().try_fold(init, f, exception=exception)

next_back() -> Option[T_co] abstractmethod

Required method.

Removes and returns an element from the end of the diterum.

Returns nil when there are no more elements.

Examples:

>>> di = diterum([1, 2, 3, 4, 5, 6])
>>> assert di.next() == Some(1)
>>> assert di.next_back() == Some(6)
>>> assert di.next_back() == Some(5)
>>> assert di.next() == Some(2)
>>> assert di.next() == Some(3)
>>> assert di.next() == Some(4)
>>> assert di.next() == nil
>>> assert di.next_back() == nil
Source code in iterum/_diterum.py
@abstractmethod
def next_back(self) -> Option[T_co]:
    """
    Required method.

    Removes and returns an element from the end of the diterum.

    Returns [nil][iterum.nil] when there are no more elements.

    Examples:

        >>> di = diterum([1, 2, 3, 4, 5, 6])
        >>> assert di.next() == Some(1)
        >>> assert di.next_back() == Some(6)
        >>> assert di.next_back() == Some(5)
        >>> assert di.next() == Some(2)
        >>> assert di.next() == Some(3)
        >>> assert di.next() == Some(4)
        >>> assert di.next() == nil
        >>> assert di.next_back() == nil
    """
    ...

len() -> int abstractmethod

Required method.

Returns the exact remaining length of the diterum.

Examples:

>>> di = diterum([1, 2, 3, 4])
>>> assert di.len() == 4
>>> assert di.next() == Some(1)
>>> assert di.len() == 3
>>> assert di.next_back() == Some(4)
>>> assert di.len() == 2
>>> assert di.collect() == [2, 3]
>>> assert di.next() == nil
>>> assert di.len() == 0
Source code in iterum/_diterum.py
@abstractmethod
def len(self) -> int:
    """
    Required method.

    Returns the exact remaining length of the diterum.

    Examples:

        >>> di = diterum([1, 2, 3, 4])
        >>> assert di.len() == 4
        >>> assert di.next() == Some(1)
        >>> assert di.len() == 3
        >>> assert di.next_back() == Some(4)
        >>> assert di.len() == 2
        >>> assert di.collect() == [2, 3]
        >>> assert di.next() == nil
        >>> assert di.len() == 0
    """
    ...

rev() -> Rev[T_co]

Reverses an diterum’s direction.

Usually, iterums iterate from left to right. After using rev(), an iterum will instead iterate from right to left.

Examples:

>>> di = diterum([1, 2, 3]).rev()
>>> assert di.next() == Some(3)
>>> assert di.next() == Some(2)
>>> assert di.next() == Some(1)
>>> assert di.next() == nil
Source code in iterum/_diterum.py
def rev(self) -> Rev[T_co]:
    """
    Reverses an diterum’s direction.

    Usually, iterums iterate from left to right. After using
    [rev()][iterum.Diterum.rev], an iterum will instead iterate from
    right to left.

    Examples:

        >>> di = diterum([1, 2, 3]).rev()
        >>> assert di.next() == Some(3)
        >>> assert di.next() == Some(2)
        >>> assert di.next() == Some(1)
        >>> assert di.next() == nil
    """
    return Rev(self)

rposition(predicate: Callable[[T_co], object]) -> Option[int]

Searches for an element in a diterum from the right, returning its index.

rposition() takes a closure that returns True or False. It applies this closure to each element of the diterum, starting from the end, and if one of them returns True, then rposition() returns Some(index). If all of them return False, it returns nil.

rposition() is short-circuiting; in other words, it will stop processing as soon as it finds a True.

Examples:

>>> di = diterum([1, 2, 3])
>>> assert di.rposition(lambda x: x == 3) == Some(2)
>>> assert di.rposition(lambda x: x == 5) == nil

Short-circuiting after first True:

>>> di = diterum([-1, 2, 3, 4])
>>> assert di.rposition(lambda x: x >= 2) == Some(3)
>>> assert di.next() == Some(-1)
Source code in iterum/_diterum.py
def rposition(self, predicate: Callable[[T_co], object], /) -> Option[int]:
    """
    Searches for an element in a diterum from the right, returning its index.

    [rposition()][iterum.Diterum.rposition] takes a closure that returns
    `True` or `False`. It applies this closure to each element of the
    diterum, starting from the end, and if one of them returns `True`, then
    [rposition()][iterum.Diterum.rposition] returns [Some(index)][iterum.Some].
    If all of them return `False`, it returns [nil][iterum.nil].

    [rposition()][iterum.Diterum.rposition] is short-circuiting; in other
    words, it will stop processing as soon as it finds a `True`.

    Examples:

        >>> di = diterum([1, 2, 3])
        >>> assert di.rposition(lambda x: x == 3) == Some(2)
        >>> assert di.rposition(lambda x: x == 5) == nil

        Short-circuiting after first `True`:
        >>> di = diterum([-1, 2, 3, 4])
        >>> assert di.rposition(lambda x: x >= 2) == Some(3)
        >>> assert di.next() == Some(-1)
    """
    len = self.len()
    return self.rev().position(predicate).map(lambda x: len - x - 1)

nth_back(n: int) -> Option[T_co]

Returns the nth element from the end of the diterum.

This is essentially the reversed version of Iterum.nth(). Although like most indexing operations, the count starts from zero, so nth_back(0) returns the first value from the end, nth_back(1) the second, and so on.

Note that all elements between the end and the returned element will be consumed, including the returned element. This also means that calling nth_back(0) multiple times on the same diterum will return different elements.

nth_back() will return nil if n is greater than or equal to the length of the diterum.

Examples:

>>> di = diterum([1, 2, 3])
>>> assert di.nth_back(2) == Some(1)

Does not rewind:

>>> di = diterum([1, 2, 3])
>>> assert di.nth_back(1) == Some(2)
>>> assert di.nth_back(1) == nil

Returns nil if there are less than n + 1 elements:

>>> di = diterum([1, 2, 3])
>>> assert di.nth_back(10) == nil
Source code in iterum/_diterum.py
def nth_back(self, n: int, /) -> Option[T_co]:
    """
    Returns the nth element from the end of the diterum.

    This is essentially the reversed version of [Iterum.nth()][iterum.Iterum.nth].
    Although like most indexing operations, the count starts from zero, so
    [nth_back(0)][iterum.Diterum.nth_back] returns the first value from the end,
    [nth_back(1)][iterum.Diterum.nth_back] the second, and so on.

    Note that all elements between the end and the returned element will be
    consumed, including the returned element. This also means that calling
    [nth_back(0)][iterum.Diterum.nth_back] multiple times on the same diterum
    will return different elements.

    [nth_back()][iterum.Diterum.nth_back] will return [nil][iterum.nil] if n
    is greater than or equal to the length of the diterum.

    Examples:

        >>> di = diterum([1, 2, 3])
        >>> assert di.nth_back(2) == Some(1)

        Does not rewind:
        >>> di = diterum([1, 2, 3])
        >>> assert di.nth_back(1) == Some(2)
        >>> assert di.nth_back(1) == nil

        Returns [nil][iterum.nil] if there are less than `n + 1` elements:
        >>> di = diterum([1, 2, 3])
        >>> assert di.nth_back(10) == nil
    """
    return self.rev().nth(n)

rfind(predicate: Callable[[T_co], object]) -> Option[T_co]

Searches for an element of a diterum from the back that satisfies a predicate.

rfind() takes a closure that returns True or False. It applies this closure to each element of the diterum, starting at the end, and if any of them return True, then rfind() returns Some(element). If they all return False, it returns nil.

rfind() is short-circuiting; in other words, it will stop processing as soon as the closure returns True.

Examples:

>>> di = diterum([1, 2, 3])
>>> assert di.rfind(lambda x: x == 2) == Some(2)
>>> assert di.rfind(lambda x: x == 5) == nil

Stops at first True:

>>> di = diterum([1, 2, 3])
>>> assert di.rfind(lambda x: x == 2) == Some(2)
>>> assert di.next_back() == Some(1)
Source code in iterum/_diterum.py
def rfind(self, predicate: Callable[[T_co], object], /) -> Option[T_co]:
    """
    Searches for an element of a diterum from the back that satisfies a predicate.

    [rfind()][iterum.Diterum.rfind] takes a closure that returns `True` or
    `False`. It applies this closure to each element of the diterum,
    starting at the end, and if any of them return `True`, then
    [rfind()][iterum.Diterum.rfind] returns [Some(element)][iterum.Some]. If
    they all return `False`, it returns [nil][iterum.nil].

    [rfind()][iterum.Diterum.rfind] is short-circuiting; in other words, it
    will stop processing as soon as the closure returns `True`.

    Examples:

        >>> di = diterum([1, 2, 3])
        >>> assert di.rfind(lambda x: x == 2) == Some(2)
        >>> assert di.rfind(lambda x: x == 5) == nil

        Stops at first `True`:
        >>> di = diterum([1, 2, 3])
        >>> assert di.rfind(lambda x: x == 2) == Some(2)
        >>> assert di.next_back() == Some(1)
    """
    return self.rev().find(predicate)

rfold(init: U, f: Callable[[U, T_co], U]) -> U

A diterum method that reduces the diterum’s elements to a single, final value, starting from the back.

This is the reverse version of Iterum.fold(): it takes elements starting from the back of the diterum.

rfold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and an element. The closure returns the value that the accumulator should have for the next iteration.

The initial value is the value the accumulator will have on the first call.

After applying this closure to every element of the diterum, rfold() returns the accumulator.

Examples:

>>> di = diterum([1, 2, 3])
>>> sum = di.rfold(0, lambda acc, x: acc + x)
>>> assert sum == 6
rfold is right-associtive
>>> numbers = [1, 2, 3, 4, 5]
>>> zero = "0"
>>> result = diterum(numbers).rfold(zero, lambda acc, x: f"({x} + {acc})")
>>> assert result == "(1 + (2 + (3 + (4 + (5 + 0)))))"
Source code in iterum/_diterum.py
def rfold(self, init: U, f: Callable[[U, T_co], U], /) -> U:
    """
    A diterum method that reduces the diterum’s elements to a single,
    final value, starting from the back.

    This is the reverse version of [Iterum.fold()][iterum.Iterum.fold]:
    it takes elements starting from the back of the diterum.

    [rfold()][iterum.Diterum.rfold] takes two arguments: an initial value,
    and a closure with two arguments: an ‘accumulator’, and an element. The
    closure returns the value that the accumulator should have for the next
    iteration.

    The initial value is the value the accumulator will have on the first call.

    After applying this closure to every element of the diterum,
    [rfold()][iterum.Diterum.rfold] returns the accumulator.

    Examples:

        >>> di = diterum([1, 2, 3])
        >>> sum = di.rfold(0, lambda acc, x: acc + x)
        >>> assert sum == 6

    rfold is right-associtive:

        ```python
        >>> numbers = [1, 2, 3, 4, 5]
        >>> zero = "0"
        >>> result = diterum(numbers).rfold(zero, lambda acc, x: f"({x} + {acc})")
        >>> assert result == "(1 + (2 + (3 + (4 + (5 + 0)))))"

        ```
    """
    return self.rev().fold(init, f)

try_rfold(init: U, f: Callable[[U, T_co], U], /, *, exception: type[BaseException] | tuple[type[BaseException], ...] = Exception) -> Option[U]

This is the reverse version of Iterum.try_fold(): it takes elements starting from the back of the diterum.

Examples:

>>> di = diterum(["1", "2", "3"])
>>> sum = di.try_rfold(0, lambda acc, x: acc + int(x), exception=TypeError)
>>> assert sum == Some(6)
Source code in iterum/_diterum.py
def try_rfold(
    self,
    init: U,
    f: Callable[[U, T_co], U],
    /,
    *,
    exception: type[BaseException] | tuple[type[BaseException], ...] = Exception,
) -> Option[U]:
    """
    This is the reverse version of [Iterum.try_fold()][iterum.Iterum.try_fold]:
    it takes elements starting from the back of the diterum.

    Examples:

        >>> di = diterum(["1", "2", "3"])
        >>> sum = di.try_rfold(0, lambda acc, x: acc + int(x), exception=TypeError)
        >>> assert sum == Some(6)
    """
    return self.rev().try_fold(init, f, exception=exception)


Ranges


iterum.seq(start: SupportsIndex | EllipsisType, end: SupportsIndex | EllipsisType | NotSetType = NotSet, /, step: SupportsIndex = 1) -> Seq | InfSeq

Count sequentially from start to end in step sizes.

If a finite end is provided, an instance of Seq is returned.

If an infinite end is provided (using ellipsis ...), an instance of InfSeq is returned.

Examples:

>>> itr = seq(3)
>>> assert itr.next() == Some(0)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> assert itr.next() == nil

Can also specify a start and step:

>>> itr = seq(3, 9, 3)
>>> assert itr.next() == Some(3)
>>> assert itr.next() == Some(6)
>>> assert itr.next() == nil

Finite ranges implement Diterum:

>>> itr = seq(3)
>>> assert itr.len() == 3
>>> assert itr.next_back() == Some(2)
>>> assert itr.next() == Some(0)

Specify an infinite range using ...:

>>> itr = seq(...)
>>> assert itr.next() == Some(0)
>>> assert itr.next() == Some(1)
>>> assert itr.next() == Some(2)
>>> # will continue forever!

Similarly a start and step can be specified:

>>> itr = seq(-10, ..., -1)
>>> assert itr.next() == Some(-10)
>>> assert itr.next() == Some(-11)
>>> assert itr.next() == Some(-12)
>>> # will continue forever!
Source code in iterum/_seq.py
def seq(
    start: SupportsIndex | EllipsisType,
    end: SupportsIndex | EllipsisType | NotSetType = NotSet,
    /,
    step: SupportsIndex = 1,
) -> Seq | InfSeq:
    """
    Count sequentially from start to end in step sizes.

    If a finite end is provided, an instance of [Seq][iterum.Seq] is returned.

    If an infinite end is provided (using ellipsis `...`), an instance of
    [InfSeq][iterum.InfSeq] is returned.

    Examples:

        >>> itr = seq(3)
        >>> assert itr.next() == Some(0)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> assert itr.next() == nil

        Can also specify a start and step:
        >>> itr = seq(3, 9, 3)
        >>> assert itr.next() == Some(3)
        >>> assert itr.next() == Some(6)
        >>> assert itr.next() == nil

        Finite ranges implement [Diterum][iterum.Diterum]:
        >>> itr = seq(3)
        >>> assert itr.len() == 3
        >>> assert itr.next_back() == Some(2)
        >>> assert itr.next() == Some(0)

        Specify an infinite range using `...`:
        >>> itr = seq(...)
        >>> assert itr.next() == Some(0)
        >>> assert itr.next() == Some(1)
        >>> assert itr.next() == Some(2)
        >>> # will continue forever!

        Similarly a start and step can be specified:
        >>> itr = seq(-10, ..., -1)
        >>> assert itr.next() == Some(-10)
        >>> assert itr.next() == Some(-11)
        >>> assert itr.next() == Some(-12)
        >>> # will continue forever!
    """

    if isinstance(end, NotSetType):
        start, end = 0, start

    elif start is ...:
        raise TypeError("Start cannot be set to '...'")

    start = operator.index(start)
    end = ... if end is ... else operator.index(end)
    step = operator.index(step)

    if end is ...:
        return InfSeq(start=start, step=step)
    else:
        return Seq(start=start, end=end, step=step)


Option


iterum.Option: TypeAlias = 'Some[T] | Nil' module-attribute

Type alias representing something which is either of type Some or Nil.

Examples:

Type annotate a function which returns Some[int] or nil:

>>> def checked_div(num: int, dem: int) -> Option[int]:
...     try:
...         return Some(num // dem)
...     except ZeroDivisionError:
...         return nil
...

Use isinstance to narrow the type:

>>> x = checked_div(10, 3)
>>> reveal_type(x)  # Type of "x" is "Some[int] | Nil"
>>> if isinstance(x, Some):
...     reveal_type(x)  # Type of "x" is "Some[int]"
... else:
...     reveal_type(x)  # Type of "x" is "Nil"
...

Alternatively use pattern matching:

>>> match x:
...     case Some(value):
...         print(f"Result: {value=}")
...     case Nil:
...         print("Cannot divide by 0")
...

}

iterum.Some

Bases: Generic[T]

Some value of type T.

Examples:

>>> x = Some(1)  # Type of "x" is "Some[int]"
>>> x
Some(1)
>>> x.is_some()
True
>>> x.unwrap()
1
Source code in iterum/_option.py
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
class Some(Generic[T]):
    """
    [Some][iterum.Some] value of type T.

    Examples:

        >>> x = Some(1)  # Type of "x" is "Some[int]"
        >>> x
        Some(1)
        >>> x.is_some()
        True
        >>> x.unwrap()
        1
    """

    __match_args__ = ("_value",)

    def __init__(self, value: T, /) -> None:
        self._value = value

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Some):
            return NotImplemented
        return self._value == other._value

    def __repr__(self) -> str:
        return f"{Some.__name__}({self._value!r})"

    def __bool__(self) -> Literal[True]:
        return True

    def and_(self, optb: O, /) -> O:
        """Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
        returns optb.

        Arguments passed to [and_][iterum.Some.and_] are eagerly evaluated; if
        you are passing the result of a function call, it is recommended to use
        [and_then][iterum.Some.and_then], which is lazily evaluated.

        Examples:

            >>> assert Some(2).and_(nil) == nil
            >>> assert nil.and_(Some("foo")) == nil
            >>> assert Some(2).and_(Some("foo")) == Some("foo")
            >>> assert nil.and_(nil) == nil

        Note: because `and` is a keyword, this method is called `and_` instead.
        """
        return optb

    def and_then(self, f: Callable[[T], O], /) -> O:
        """Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
        calls `f` with the wrapped value and returns the result.

        Examples:


            >>> MAX_U32 = (1 << 32) - 1
            >>> def checked_sq_u32(x: int) -> Option[int]:
            ...     sq = x * x
            ...     if sq > MAX_U32:
            ...         return nil
            ...     return Some(sq)
            ...
            >>> assert Some(2).and_then(checked_sq_u32) == Some(4)
            >>> assert Some(1_000_000).and_then(checked_sq_u32) == nil
            >>> assert nil.and_then(checked_sq_u32) == nil
        """
        return f(self._value)

    def expect(self, msg: str, /) -> T:
        """Returns the contained [Some][iterum.Some] value, consuming the self value.

        Examples:

            >>> x = Some("value")
            >>> assert x.expect("fruits are healthy") == "value"

            >>> try:
            ...     nil.expect("fruits are healthy")
            ... except ExpectNilError as ex:
            ...     print(ex)
            ...
            fruits are healthy

        Raises:
            ExpectNilError: if the value is a [nil][iterum.nil] with a custom
                message provided by msg.
        """
        return self._value

    def filter(self, predicate: Callable[[T], object], /) -> Option[T]:
        """Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
        calls `predicate` with the wrapped value and returns:

            - [Some(value)][iterum.Some] if the predicate returns `True`
            - [nil][iterum.nil] if the predicate returns `False`

        Examples:

            >>> assert nil.filter(lambda x: x % 2 == 0) == nil
            >>> assert Some(3).filter(lambda x: x % 2 == 0) == nil
            >>> assert Some(4).filter(lambda x: x % 2 == 0) == Some(4)
        """
        return self if predicate(self._value) else Nil()

    def flatten(self: Some[O]) -> O:
        """Converts from `Option[Option[T]]` to `Option[T]`.

        Examples:

            >>> assert Some(Some(6)).flatten() == Some(6)
            >>> assert Some(nil).flatten() == nil
            >>> assert nil.flatten() == nil
        """
        if isinstance(self._value, (Some, Nil)):
            return self._value
        else:
            raise TypeError(f"Cannot flatten type: Some({type(self._value).__name__})")

    def get_or_insert(self, value: T, /) -> Swap[Some[T], T]:
        """Inserts value into the option if it is [nil][iterum.nil], then returns a
        tuple of the resulting option and the returned value.

        See also [insert][iterum.Some.insert], which updates the value even if
        the option already contains a value.

        Examples:

            >>> opt = nil
            >>> opt, value = opt.get_or_insert(5)
            >>> assert value == 5
            >>> assert opt == Some(5)

            >>> opt = Some(3)
            >>> opt, value = opt.get_or_insert(5)
            >>> assert value == 3
            >>> assert opt == Some(3)

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> assert Some(10).get_or_insert(5).returned == 10
            >>> assert nil.get_or_insert(5).returned == 5

            >>> assert Some(10).get_or_insert(5).inserted == Some(10)
            >>> assert nil.get_or_insert(5).inserted == Some(5)
        """
        return Swap(Some(self._value), self._value)

    def get_or_insert_with(self, f: Callable[[], T], /) -> Swap[Some[T], T]:
        """Inserts a value computed from `f` into the option if it is
        [nil][iterum.nil], then returns a tuple of the resulting option and the
        returned value.

        Examples:

            >>> opt = nil
            >>> opt, value = opt.get_or_insert_with(lambda: 5)
            >>> assert value == 5
            >>> assert opt == Some(5)

            >>> opt = Some(3)
            >>> opt, value = opt.get_or_insert_with(lambda: 5)
            >>> assert value == 3
            >>> assert opt == Some(3)

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(10).get_or_insert_with(lambda: 5)
            >>> assert swap.inserted == Some(10)
            >>> assert swap.returned == 10

            >>> swap = nil.get_or_insert_with(lambda: 5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == 5
        """
        return Swap(Some(self._value), self._value)

    def insert(self, value: T, /) -> Swap[Some[T], T]:
        """Inserts value into the option, then returns a tuple of the resulting
        option and the returned value.

        If the option already contains a value, the old value is dropped.

        See also [get_or_insert][iterum.Some.get_or_insert], which doesn’t
        update the value if the option already contains a value.

        Examples:

            >>> opt = nil
            >>> opt, value = opt.insert(1)
            >>> assert value == 1
            >>> assert opt == Some(1)

            >>> opt = Some(3)
            >>> opt, value = opt.insert(1)
            >>> assert value == 1
            >>> assert opt == Some(1)

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(10).insert(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == 5

            >>> swap = nil.insert(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == 5
        """
        self._value = value
        return Swap(Some(self._value), self._value)

    def is_nil(self) -> Literal[False]:
        """Returns `True` if the option is a [nil][iterum.nil] value.

        Examples:

            >>> assert Some(2).is_nil() is False
            >>> assert nil.is_nil() is True
        """
        return False

    def is_some(self) -> Literal[True]:
        """Returns `True` if the option is a Some value.

        Examples:

            >>> assert Some(2).is_some() is True
            >>> assert nil.is_some() is False
        """
        return True

    def is_some_and(self, f: Callable[[T], object]) -> bool:
        """Returns `True` if the option is a [Some][iterum.Some] and the value
        inside of it matches a predicate.

        Examples:

            >>> assert Some(2).is_some_and(lambda x: x > 1) is True
            >>> assert Some(0).is_some_and(lambda x: x > 1) is False
            >>> assert nil.is_some_and(lambda x: x > 1) is False
        """
        return bool(f(self.unwrap()))

    def iter(self) -> iterum[T]:
        """Returns an iterator over the possibly contained value.

        Examples:

            >>> assert Some(4).iter().next() == Some(4)
            >>> assert nil.iter().next() == nil
        """
        from ._iterum import iterum

        return iterum([self._value])

    def map(self, f: Callable[[T], U], /) -> Some[U]:
        """Maps an [Option[T]][iterum.Option] to [Option[U]][iterum.Option] by
        applying a function to a contained value (if [Some][iterum.Some]) or
        returns [nil][iterum.nil] (if [Nil][iterum.Nil]).

        Examples:

            >>> assert Some("Hello, World!").map(len) == Some(13)
            >>> assert nil.map(len) == nil
        """
        return Some(f(self._value))

    def map_or(self, default: U, f: Callable[[T], U], /) -> U:
        """
        Returns the provided default result (if [nil][iterum.nil]), or applies a
        function to the contained value (if any).

        Arguments passed to [map_or][iterum.Some.map_or] are eagerly evaluated;
        if you are passing the result of a function call, it is recommended to
        use [map_or_else][iterum.Some.map_or_else], which is lazily evaluated.

        Examples:

            >>> assert Some("foo").map_or(42, len) == 3
            >>> assert nil.map_or(42, len) == 42
        """
        return f(self._value)

    def map_or_else(self, default: Callable[[], U], f: Callable[[T], U], /) -> U:
        """
        Computes a default function result (if [nil][iterum.nil]), or applies a
        different function to the contained value (if any).

        Examples:

            >>> k = 21
            >>> assert Some("foo").map_or_else(lambda: 2 * k, len) == 3
            >>> assert nil.map_or_else(lambda: 2 * k, len) == 42
        """
        return f(self._value)

    def ok_or(self, err: Exception, /) -> T:
        """Unwraps the option returning the value if [Some][iterum.Some] or raises
        the provided exception if [nil][iterum.nil].

        Arguments passed to [ok_or][iterum.Some.ok_or] are eagerly evaluated; if
        you are passing the result of a function call, it is recommended to use
        [ok_or_else][iterum.Some.ok_or_else], which is lazily evaluated.

        Examples:

            >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

            >>> try:
            ...     nil.ok_or(RuntimeError("oh no!"))
            ... except RuntimeError as ex:
            ...     print(ex)
            ...
            oh no!
        """
        return self._value

    def ok_or_else(self, err: Callable[[], Exception], /) -> T:
        """Unwraps the option returning the value if [Some][iterum.Some] or raises
        the exception returned by the provided callable if [nil][iterum.nil].

        Examples:

            >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

            >>> try:
            ...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
            ... except AssertionError as ex:
            ...     print(ex)
            ...
            oopsy!
        """
        return self._value

    def or_(self, optb: Option[T], /) -> Some[T]:
        """Returns the option if it contains a value, otherwise returns optb.

        Arguments passed to [or_][iterum.Some.or_] are eagerly evaluated; if you
        are passing the result of a function call, it is recommended to use
        [or_else][iterum.Some.or_else], which is lazily evaluated.

        Examples:

            >>> assert Some(2).or_(nil) == Some(2)
            >>> assert nil.or_(Some(100)) == Some(100)
            >>> assert Some(2).or_(Some(100)) == Some(2)
            >>> assert nil.or_(nil) == nil

        Note: because `or` is a keyword, this method is called `or_` instead.
        """
        # 'or' is a keyword, so instead we use 'or_'
        return self

    def or_else(self, f: Callable[[], Option[T]], /) -> Some[T]:
        """Returns the option if it contains a value, otherwise calls `f` and
        returns the result.

        Examples:

            >>> def nobody() -> Option[str]:
            ...     return nil
            ...
            >>> def vikings() -> Option[str]:
            ...     return Some("vikings")
            ...
            >>> assert Some("barbarians").or_else(vikings) == Some("barbarians")
            >>> assert nil.or_else(vikings) == Some("vikings")
            >>> assert nil.or_else(nobody) == nil
        """
        return self

    def replace(self, value: T, /) -> Swap[Some[T], Some[T]]:
        """Replaces the actual value in the option by the value given in parameter,
        returning a tuple of the resulting option and the returned old value if
        present.

        Examples:

            >>> x = Some(2)
            >>> new, old = x.replace(5)
            >>> assert new == Some(5)
            >>> assert old == Some(2)

            >>> x = nil
            >>> new, old = x.replace(5)
            >>> assert new == Some(5)
            >>> assert old == nil

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(10).replace(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == Some(10)

            >>> swap = nil.replace(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == nil
        """
        old = self._value
        self._value = value
        return Swap(Some(self._value), Some(old))

    def take(self) -> Swap[Nil, Some[T]]:
        """Takes the value out of the option, returning a tuple of the resulting
        nil and the old option.

        Examples:

            >>> x = Some(2)
            >>> new, old = x.take()
            >>> assert new == nil
            >>> assert old == Some(2)

            >>> x = nil
            >>> new, old = x.take()
            >>> assert new == nil
            >>> assert old == nil

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(2).take()
            >>> assert swap.inserted == nil
            >>> assert swap.returned == Some(2)

            >>> swap = nil.take()
            >>> assert swap.inserted == nil
            >>> assert swap.returned == nil
        """
        return Swap(nil, self)

    # transpose ... without a Result concept there isn't any value

    def unwrap(self) -> T:
        """Returns the contained [Some][iterum.Some] value.

        Examples:

            >>> assert Some("air").unwrap() == "air"

            >>> try:
            ...     nil.unwrap()
            ... except UnwrapNilError as ex:
            ...     print("Attempted to unwrap a nil!")
            ...
            Attempted to unwrap a nil!

        Raises:
            UnwrapNilError: if the value is a [nil][iterum.nil].
        """
        return self._value

    def unwrap_or(self, default: T, /) -> T:
        """
        Returns the contained [Some][iterum.Some] value or a provided default.

        Arguments passed to [unwrap_or][iterum.Some.unwrap_or] are eagerly
        evaluated; if you are passing the result of a function call, it is
        recommended to use [unwrap_or_else][iterum.Some.unwrap_or_else], which
        is lazily evaluated.

        Examples:

            >>> assert Some("car").unwrap_or("bike") == "car"
            >>> assert nil.unwrap_or("bike") == "bike"
        """
        return self._value

    def unwrap_or_else(self, f: Callable[[], T], /) -> T:
        """Returns the contained [Some][iterum.Some] value or computes it from a closure.

        Examples:

            >>> k = 10
            >>> assert Some(4).unwrap_or_else(lambda: 2 * k) == 4
            >>> assert nil.unwrap_or_else(lambda: 2 * k) == 20
        """
        return self._value

    def unzip(self: Some[tuple[U, V]]) -> tuple[Some[U], Some[V]]:
        """Unzips an option containing a tuple of two options.

        If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`.
        Otherwise, `(nil, nil)` is returned.

        Examples:

            >>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
            >>> assert nil.unzip() == (nil, nil)
        """
        left, right = self._value
        return Some(left), Some(right)

    @overload
    def xor(self, optb: Some[T], /) -> Nil:
        ...

    @overload
    def xor(self, optb: Nil, /) -> Some[T]:
        ...

    def xor(self, optb: Option[T], /) -> Option[T]:
        """
        Returns [Some][iterum.Some] if exactly one of `self`, `optb` is
        [Some][iterum.Some], otherwise returns [nil][iterum.nil].

        Examples:

            >>> assert Some(2).xor(nil) == Some(2)
            >>> assert nil.xor(Some(100)) == Some(100)
            >>> assert Some(2).xor(Some(100)) == nil
            >>> assert nil.xor(nil) == nil
        """
        return self if isinstance(optb, Nil) else nil

    @overload
    def zip(self, other: Some[U], /) -> Some[tuple[T, U]]:
        ...

    @overload
    def zip(self, other: Nil, /) -> Nil:
        ...

    def zip(self, other: Option[U], /) -> Option[tuple[T, U]]:
        """
        Zips `self` with another option.

        If `self` is `Some(s)` and `other` is `Some(o)`,
        this method returns `Some((s, o))`.
        Otherwise, [nil][iterum.nil] is returned.

        Examples:

            >>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
            >>> assert Some(1).zip(nil) == nil
            >>> assert nil.zip(nil) == nil
        """
        return nil if isinstance(other, Nil) else Some((self._value, other._value))

and_(optb: O) -> O

Returns nil if the option is nil, otherwise returns optb.

Arguments passed to and_ are eagerly evaluated; if you are passing the result of a function call, it is recommended to use and_then, which is lazily evaluated.

Examples:

>>> assert Some(2).and_(nil) == nil
>>> assert nil.and_(Some("foo")) == nil
>>> assert Some(2).and_(Some("foo")) == Some("foo")
>>> assert nil.and_(nil) == nil

Note: because and is a keyword, this method is called and_ instead.

Source code in iterum/_option.py
def and_(self, optb: O, /) -> O:
    """Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
    returns optb.

    Arguments passed to [and_][iterum.Some.and_] are eagerly evaluated; if
    you are passing the result of a function call, it is recommended to use
    [and_then][iterum.Some.and_then], which is lazily evaluated.

    Examples:

        >>> assert Some(2).and_(nil) == nil
        >>> assert nil.and_(Some("foo")) == nil
        >>> assert Some(2).and_(Some("foo")) == Some("foo")
        >>> assert nil.and_(nil) == nil

    Note: because `and` is a keyword, this method is called `and_` instead.
    """
    return optb

and_then(f: Callable[[T], O]) -> O

Returns nil if the option is nil, otherwise calls f with the wrapped value and returns the result.

Examples:

>>> MAX_U32 = (1 << 32) - 1
>>> def checked_sq_u32(x: int) -> Option[int]:
...     sq = x * x
...     if sq > MAX_U32:
...         return nil
...     return Some(sq)
...
>>> assert Some(2).and_then(checked_sq_u32) == Some(4)
>>> assert Some(1_000_000).and_then(checked_sq_u32) == nil
>>> assert nil.and_then(checked_sq_u32) == nil
Source code in iterum/_option.py
def and_then(self, f: Callable[[T], O], /) -> O:
    """Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
    calls `f` with the wrapped value and returns the result.

    Examples:


        >>> MAX_U32 = (1 << 32) - 1
        >>> def checked_sq_u32(x: int) -> Option[int]:
        ...     sq = x * x
        ...     if sq > MAX_U32:
        ...         return nil
        ...     return Some(sq)
        ...
        >>> assert Some(2).and_then(checked_sq_u32) == Some(4)
        >>> assert Some(1_000_000).and_then(checked_sq_u32) == nil
        >>> assert nil.and_then(checked_sq_u32) == nil
    """
    return f(self._value)

expect(msg: str) -> T

Returns the contained Some value, consuming the self value.

Examples:

>>> x = Some("value")
>>> assert x.expect("fruits are healthy") == "value"
>>> try:
...     nil.expect("fruits are healthy")
... except ExpectNilError as ex:
...     print(ex)
...
fruits are healthy

Raises:

Type Description
ExpectNilError

if the value is a nil with a custom message provided by msg.

Source code in iterum/_option.py
def expect(self, msg: str, /) -> T:
    """Returns the contained [Some][iterum.Some] value, consuming the self value.

    Examples:

        >>> x = Some("value")
        >>> assert x.expect("fruits are healthy") == "value"

        >>> try:
        ...     nil.expect("fruits are healthy")
        ... except ExpectNilError as ex:
        ...     print(ex)
        ...
        fruits are healthy

    Raises:
        ExpectNilError: if the value is a [nil][iterum.nil] with a custom
            message provided by msg.
    """
    return self._value

filter(predicate: Callable[[T], object]) -> Option[T]

Returns nil if the option is nil, otherwise calls predicate with the wrapped value and returns:

- [Some(value)][iterum.Some] if the predicate returns `True`
- [nil][iterum.nil] if the predicate returns `False`

Examples:

>>> assert nil.filter(lambda x: x % 2 == 0) == nil
>>> assert Some(3).filter(lambda x: x % 2 == 0) == nil
>>> assert Some(4).filter(lambda x: x % 2 == 0) == Some(4)
Source code in iterum/_option.py
def filter(self, predicate: Callable[[T], object], /) -> Option[T]:
    """Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
    calls `predicate` with the wrapped value and returns:

        - [Some(value)][iterum.Some] if the predicate returns `True`
        - [nil][iterum.nil] if the predicate returns `False`

    Examples:

        >>> assert nil.filter(lambda x: x % 2 == 0) == nil
        >>> assert Some(3).filter(lambda x: x % 2 == 0) == nil
        >>> assert Some(4).filter(lambda x: x % 2 == 0) == Some(4)
    """
    return self if predicate(self._value) else Nil()

flatten() -> O

Converts from Option[Option[T]] to Option[T].

Examples:

>>> assert Some(Some(6)).flatten() == Some(6)
>>> assert Some(nil).flatten() == nil
>>> assert nil.flatten() == nil
Source code in iterum/_option.py
def flatten(self: Some[O]) -> O:
    """Converts from `Option[Option[T]]` to `Option[T]`.

    Examples:

        >>> assert Some(Some(6)).flatten() == Some(6)
        >>> assert Some(nil).flatten() == nil
        >>> assert nil.flatten() == nil
    """
    if isinstance(self._value, (Some, Nil)):
        return self._value
    else:
        raise TypeError(f"Cannot flatten type: Some({type(self._value).__name__})")

get_or_insert(value: T) -> Swap[Some[T], T]

Inserts value into the option if it is nil, then returns a tuple of the resulting option and the returned value.

See also insert, which updates the value even if the option already contains a value.

Examples:

>>> opt = nil
>>> opt, value = opt.get_or_insert(5)
>>> assert value == 5
>>> assert opt == Some(5)
>>> opt = Some(3)
>>> opt, value = opt.get_or_insert(5)
>>> assert value == 3
>>> assert opt == Some(3)

Alternatively, access the named attributes of Swap, inserted and returned:

>>> assert Some(10).get_or_insert(5).returned == 10
>>> assert nil.get_or_insert(5).returned == 5
>>> assert Some(10).get_or_insert(5).inserted == Some(10)
>>> assert nil.get_or_insert(5).inserted == Some(5)
Source code in iterum/_option.py
def get_or_insert(self, value: T, /) -> Swap[Some[T], T]:
    """Inserts value into the option if it is [nil][iterum.nil], then returns a
    tuple of the resulting option and the returned value.

    See also [insert][iterum.Some.insert], which updates the value even if
    the option already contains a value.

    Examples:

        >>> opt = nil
        >>> opt, value = opt.get_or_insert(5)
        >>> assert value == 5
        >>> assert opt == Some(5)

        >>> opt = Some(3)
        >>> opt, value = opt.get_or_insert(5)
        >>> assert value == 3
        >>> assert opt == Some(3)

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> assert Some(10).get_or_insert(5).returned == 10
        >>> assert nil.get_or_insert(5).returned == 5

        >>> assert Some(10).get_or_insert(5).inserted == Some(10)
        >>> assert nil.get_or_insert(5).inserted == Some(5)
    """
    return Swap(Some(self._value), self._value)

get_or_insert_with(f: Callable[[], T]) -> Swap[Some[T], T]

Inserts a value computed from f into the option if it is nil, then returns a tuple of the resulting option and the returned value.

Examples:

>>> opt = nil
>>> opt, value = opt.get_or_insert_with(lambda: 5)
>>> assert value == 5
>>> assert opt == Some(5)
>>> opt = Some(3)
>>> opt, value = opt.get_or_insert_with(lambda: 5)
>>> assert value == 3
>>> assert opt == Some(3)

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(10).get_or_insert_with(lambda: 5)
>>> assert swap.inserted == Some(10)
>>> assert swap.returned == 10
>>> swap = nil.get_or_insert_with(lambda: 5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == 5
Source code in iterum/_option.py
def get_or_insert_with(self, f: Callable[[], T], /) -> Swap[Some[T], T]:
    """Inserts a value computed from `f` into the option if it is
    [nil][iterum.nil], then returns a tuple of the resulting option and the
    returned value.

    Examples:

        >>> opt = nil
        >>> opt, value = opt.get_or_insert_with(lambda: 5)
        >>> assert value == 5
        >>> assert opt == Some(5)

        >>> opt = Some(3)
        >>> opt, value = opt.get_or_insert_with(lambda: 5)
        >>> assert value == 3
        >>> assert opt == Some(3)

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(10).get_or_insert_with(lambda: 5)
        >>> assert swap.inserted == Some(10)
        >>> assert swap.returned == 10

        >>> swap = nil.get_or_insert_with(lambda: 5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5
    """
    return Swap(Some(self._value), self._value)

insert(value: T) -> Swap[Some[T], T]

Inserts value into the option, then returns a tuple of the resulting option and the returned value.

If the option already contains a value, the old value is dropped.

See also get_or_insert, which doesn’t update the value if the option already contains a value.

Examples:

>>> opt = nil
>>> opt, value = opt.insert(1)
>>> assert value == 1
>>> assert opt == Some(1)
>>> opt = Some(3)
>>> opt, value = opt.insert(1)
>>> assert value == 1
>>> assert opt == Some(1)

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(10).insert(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == 5
>>> swap = nil.insert(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == 5
Source code in iterum/_option.py
def insert(self, value: T, /) -> Swap[Some[T], T]:
    """Inserts value into the option, then returns a tuple of the resulting
    option and the returned value.

    If the option already contains a value, the old value is dropped.

    See also [get_or_insert][iterum.Some.get_or_insert], which doesn’t
    update the value if the option already contains a value.

    Examples:

        >>> opt = nil
        >>> opt, value = opt.insert(1)
        >>> assert value == 1
        >>> assert opt == Some(1)

        >>> opt = Some(3)
        >>> opt, value = opt.insert(1)
        >>> assert value == 1
        >>> assert opt == Some(1)

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(10).insert(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5

        >>> swap = nil.insert(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5
    """
    self._value = value
    return Swap(Some(self._value), self._value)

is_nil() -> Literal[False]

Returns True if the option is a nil value.

Examples:

>>> assert Some(2).is_nil() is False
>>> assert nil.is_nil() is True
Source code in iterum/_option.py
def is_nil(self) -> Literal[False]:
    """Returns `True` if the option is a [nil][iterum.nil] value.

    Examples:

        >>> assert Some(2).is_nil() is False
        >>> assert nil.is_nil() is True
    """
    return False

is_some() -> Literal[True]

Returns True if the option is a Some value.

Examples:

>>> assert Some(2).is_some() is True
>>> assert nil.is_some() is False
Source code in iterum/_option.py
def is_some(self) -> Literal[True]:
    """Returns `True` if the option is a Some value.

    Examples:

        >>> assert Some(2).is_some() is True
        >>> assert nil.is_some() is False
    """
    return True

is_some_and(f: Callable[[T], object]) -> bool

Returns True if the option is a Some and the value inside of it matches a predicate.

Examples:

>>> assert Some(2).is_some_and(lambda x: x > 1) is True
>>> assert Some(0).is_some_and(lambda x: x > 1) is False
>>> assert nil.is_some_and(lambda x: x > 1) is False
Source code in iterum/_option.py
def is_some_and(self, f: Callable[[T], object]) -> bool:
    """Returns `True` if the option is a [Some][iterum.Some] and the value
    inside of it matches a predicate.

    Examples:

        >>> assert Some(2).is_some_and(lambda x: x > 1) is True
        >>> assert Some(0).is_some_and(lambda x: x > 1) is False
        >>> assert nil.is_some_and(lambda x: x > 1) is False
    """
    return bool(f(self.unwrap()))

iter() -> iterum[T]

Returns an iterator over the possibly contained value.

Examples:

>>> assert Some(4).iter().next() == Some(4)
>>> assert nil.iter().next() == nil
Source code in iterum/_option.py
def iter(self) -> iterum[T]:
    """Returns an iterator over the possibly contained value.

    Examples:

        >>> assert Some(4).iter().next() == Some(4)
        >>> assert nil.iter().next() == nil
    """
    from ._iterum import iterum

    return iterum([self._value])

map(f: Callable[[T], U]) -> Some[U]

Maps an Option[T] to Option[U] by applying a function to a contained value (if Some) or returns nil (if Nil).

Examples:

>>> assert Some("Hello, World!").map(len) == Some(13)
>>> assert nil.map(len) == nil
Source code in iterum/_option.py
def map(self, f: Callable[[T], U], /) -> Some[U]:
    """Maps an [Option[T]][iterum.Option] to [Option[U]][iterum.Option] by
    applying a function to a contained value (if [Some][iterum.Some]) or
    returns [nil][iterum.nil] (if [Nil][iterum.Nil]).

    Examples:

        >>> assert Some("Hello, World!").map(len) == Some(13)
        >>> assert nil.map(len) == nil
    """
    return Some(f(self._value))

map_or(default: U, f: Callable[[T], U]) -> U

Returns the provided default result (if nil), or applies a function to the contained value (if any).

Arguments passed to map_or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use map_or_else, which is lazily evaluated.

Examples:

>>> assert Some("foo").map_or(42, len) == 3
>>> assert nil.map_or(42, len) == 42
Source code in iterum/_option.py
def map_or(self, default: U, f: Callable[[T], U], /) -> U:
    """
    Returns the provided default result (if [nil][iterum.nil]), or applies a
    function to the contained value (if any).

    Arguments passed to [map_or][iterum.Some.map_or] are eagerly evaluated;
    if you are passing the result of a function call, it is recommended to
    use [map_or_else][iterum.Some.map_or_else], which is lazily evaluated.

    Examples:

        >>> assert Some("foo").map_or(42, len) == 3
        >>> assert nil.map_or(42, len) == 42
    """
    return f(self._value)

map_or_else(default: Callable[[], U], f: Callable[[T], U]) -> U

Computes a default function result (if nil), or applies a different function to the contained value (if any).

Examples:

>>> k = 21
>>> assert Some("foo").map_or_else(lambda: 2 * k, len) == 3
>>> assert nil.map_or_else(lambda: 2 * k, len) == 42
Source code in iterum/_option.py
def map_or_else(self, default: Callable[[], U], f: Callable[[T], U], /) -> U:
    """
    Computes a default function result (if [nil][iterum.nil]), or applies a
    different function to the contained value (if any).

    Examples:

        >>> k = 21
        >>> assert Some("foo").map_or_else(lambda: 2 * k, len) == 3
        >>> assert nil.map_or_else(lambda: 2 * k, len) == 42
    """
    return f(self._value)

ok_or(err: Exception) -> T

Unwraps the option returning the value if Some or raises the provided exception if nil.

Arguments passed to ok_or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use ok_or_else, which is lazily evaluated.

Examples:

>>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"
>>> try:
...     nil.ok_or(RuntimeError("oh no!"))
... except RuntimeError as ex:
...     print(ex)
...
oh no!
Source code in iterum/_option.py
def ok_or(self, err: Exception, /) -> T:
    """Unwraps the option returning the value if [Some][iterum.Some] or raises
    the provided exception if [nil][iterum.nil].

    Arguments passed to [ok_or][iterum.Some.ok_or] are eagerly evaluated; if
    you are passing the result of a function call, it is recommended to use
    [ok_or_else][iterum.Some.ok_or_else], which is lazily evaluated.

    Examples:

        >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

        >>> try:
        ...     nil.ok_or(RuntimeError("oh no!"))
        ... except RuntimeError as ex:
        ...     print(ex)
        ...
        oh no!
    """
    return self._value

ok_or_else(err: Callable[[], Exception]) -> T

Unwraps the option returning the value if Some or raises the exception returned by the provided callable if nil.

Examples:

>>> assert Some("foo").ok_or_else(AssertionError) == "foo"
>>> try:
...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
... except AssertionError as ex:
...     print(ex)
...
oopsy!
Source code in iterum/_option.py
def ok_or_else(self, err: Callable[[], Exception], /) -> T:
    """Unwraps the option returning the value if [Some][iterum.Some] or raises
    the exception returned by the provided callable if [nil][iterum.nil].

    Examples:

        >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

        >>> try:
        ...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
        ... except AssertionError as ex:
        ...     print(ex)
        ...
        oopsy!
    """
    return self._value

or_(optb: Option[T]) -> Some[T]

Returns the option if it contains a value, otherwise returns optb.

Arguments passed to or_ are eagerly evaluated; if you are passing the result of a function call, it is recommended to use or_else, which is lazily evaluated.

Examples:

>>> assert Some(2).or_(nil) == Some(2)
>>> assert nil.or_(Some(100)) == Some(100)
>>> assert Some(2).or_(Some(100)) == Some(2)
>>> assert nil.or_(nil) == nil

Note: because or is a keyword, this method is called or_ instead.

Source code in iterum/_option.py
def or_(self, optb: Option[T], /) -> Some[T]:
    """Returns the option if it contains a value, otherwise returns optb.

    Arguments passed to [or_][iterum.Some.or_] are eagerly evaluated; if you
    are passing the result of a function call, it is recommended to use
    [or_else][iterum.Some.or_else], which is lazily evaluated.

    Examples:

        >>> assert Some(2).or_(nil) == Some(2)
        >>> assert nil.or_(Some(100)) == Some(100)
        >>> assert Some(2).or_(Some(100)) == Some(2)
        >>> assert nil.or_(nil) == nil

    Note: because `or` is a keyword, this method is called `or_` instead.
    """
    # 'or' is a keyword, so instead we use 'or_'
    return self

or_else(f: Callable[[], Option[T]]) -> Some[T]

Returns the option if it contains a value, otherwise calls f and returns the result.

Examples:

>>> def nobody() -> Option[str]:
...     return nil
...
>>> def vikings() -> Option[str]:
...     return Some("vikings")
...
>>> assert Some("barbarians").or_else(vikings) == Some("barbarians")
>>> assert nil.or_else(vikings) == Some("vikings")
>>> assert nil.or_else(nobody) == nil
Source code in iterum/_option.py
def or_else(self, f: Callable[[], Option[T]], /) -> Some[T]:
    """Returns the option if it contains a value, otherwise calls `f` and
    returns the result.

    Examples:

        >>> def nobody() -> Option[str]:
        ...     return nil
        ...
        >>> def vikings() -> Option[str]:
        ...     return Some("vikings")
        ...
        >>> assert Some("barbarians").or_else(vikings) == Some("barbarians")
        >>> assert nil.or_else(vikings) == Some("vikings")
        >>> assert nil.or_else(nobody) == nil
    """
    return self

replace(value: T) -> Swap[Some[T], Some[T]]

Replaces the actual value in the option by the value given in parameter, returning a tuple of the resulting option and the returned old value if present.

Examples:

>>> x = Some(2)
>>> new, old = x.replace(5)
>>> assert new == Some(5)
>>> assert old == Some(2)
>>> x = nil
>>> new, old = x.replace(5)
>>> assert new == Some(5)
>>> assert old == nil

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(10).replace(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == Some(10)
>>> swap = nil.replace(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == nil
Source code in iterum/_option.py
def replace(self, value: T, /) -> Swap[Some[T], Some[T]]:
    """Replaces the actual value in the option by the value given in parameter,
    returning a tuple of the resulting option and the returned old value if
    present.

    Examples:

        >>> x = Some(2)
        >>> new, old = x.replace(5)
        >>> assert new == Some(5)
        >>> assert old == Some(2)

        >>> x = nil
        >>> new, old = x.replace(5)
        >>> assert new == Some(5)
        >>> assert old == nil

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(10).replace(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == Some(10)

        >>> swap = nil.replace(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == nil
    """
    old = self._value
    self._value = value
    return Swap(Some(self._value), Some(old))

take() -> Swap[Nil, Some[T]]

Takes the value out of the option, returning a tuple of the resulting nil and the old option.

Examples:

>>> x = Some(2)
>>> new, old = x.take()
>>> assert new == nil
>>> assert old == Some(2)
>>> x = nil
>>> new, old = x.take()
>>> assert new == nil
>>> assert old == nil

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(2).take()
>>> assert swap.inserted == nil
>>> assert swap.returned == Some(2)
>>> swap = nil.take()
>>> assert swap.inserted == nil
>>> assert swap.returned == nil
Source code in iterum/_option.py
def take(self) -> Swap[Nil, Some[T]]:
    """Takes the value out of the option, returning a tuple of the resulting
    nil and the old option.

    Examples:

        >>> x = Some(2)
        >>> new, old = x.take()
        >>> assert new == nil
        >>> assert old == Some(2)

        >>> x = nil
        >>> new, old = x.take()
        >>> assert new == nil
        >>> assert old == nil

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(2).take()
        >>> assert swap.inserted == nil
        >>> assert swap.returned == Some(2)

        >>> swap = nil.take()
        >>> assert swap.inserted == nil
        >>> assert swap.returned == nil
    """
    return Swap(nil, self)

unwrap() -> T

Returns the contained Some value.

Examples:

>>> assert Some("air").unwrap() == "air"
>>> try:
...     nil.unwrap()
... except UnwrapNilError as ex:
...     print("Attempted to unwrap a nil!")
...
Attempted to unwrap a nil!

Raises:

Type Description
UnwrapNilError

if the value is a nil.

Source code in iterum/_option.py
def unwrap(self) -> T:
    """Returns the contained [Some][iterum.Some] value.

    Examples:

        >>> assert Some("air").unwrap() == "air"

        >>> try:
        ...     nil.unwrap()
        ... except UnwrapNilError as ex:
        ...     print("Attempted to unwrap a nil!")
        ...
        Attempted to unwrap a nil!

    Raises:
        UnwrapNilError: if the value is a [nil][iterum.nil].
    """
    return self._value

unwrap_or(default: T) -> T

Returns the contained Some value or a provided default.

Arguments passed to unwrap_or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use unwrap_or_else, which is lazily evaluated.

Examples:

>>> assert Some("car").unwrap_or("bike") == "car"
>>> assert nil.unwrap_or("bike") == "bike"
Source code in iterum/_option.py
def unwrap_or(self, default: T, /) -> T:
    """
    Returns the contained [Some][iterum.Some] value or a provided default.

    Arguments passed to [unwrap_or][iterum.Some.unwrap_or] are eagerly
    evaluated; if you are passing the result of a function call, it is
    recommended to use [unwrap_or_else][iterum.Some.unwrap_or_else], which
    is lazily evaluated.

    Examples:

        >>> assert Some("car").unwrap_or("bike") == "car"
        >>> assert nil.unwrap_or("bike") == "bike"
    """
    return self._value

unwrap_or_else(f: Callable[[], T]) -> T

Returns the contained Some value or computes it from a closure.

Examples:

>>> k = 10
>>> assert Some(4).unwrap_or_else(lambda: 2 * k) == 4
>>> assert nil.unwrap_or_else(lambda: 2 * k) == 20
Source code in iterum/_option.py
def unwrap_or_else(self, f: Callable[[], T], /) -> T:
    """Returns the contained [Some][iterum.Some] value or computes it from a closure.

    Examples:

        >>> k = 10
        >>> assert Some(4).unwrap_or_else(lambda: 2 * k) == 4
        >>> assert nil.unwrap_or_else(lambda: 2 * k) == 20
    """
    return self._value

unzip() -> tuple[Some[U], Some[V]]

Unzips an option containing a tuple of two options.

If self is Some((a, b)) this method returns (Some(a), Some(b)). Otherwise, (nil, nil) is returned.

Examples:

>>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
>>> assert nil.unzip() == (nil, nil)
Source code in iterum/_option.py
def unzip(self: Some[tuple[U, V]]) -> tuple[Some[U], Some[V]]:
    """Unzips an option containing a tuple of two options.

    If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`.
    Otherwise, `(nil, nil)` is returned.

    Examples:

        >>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
        >>> assert nil.unzip() == (nil, nil)
    """
    left, right = self._value
    return Some(left), Some(right)

xor(optb: Option[T]) -> Option[T]

Returns Some if exactly one of self, optb is Some, otherwise returns nil.

Examples:

>>> assert Some(2).xor(nil) == Some(2)
>>> assert nil.xor(Some(100)) == Some(100)
>>> assert Some(2).xor(Some(100)) == nil
>>> assert nil.xor(nil) == nil
Source code in iterum/_option.py
def xor(self, optb: Option[T], /) -> Option[T]:
    """
    Returns [Some][iterum.Some] if exactly one of `self`, `optb` is
    [Some][iterum.Some], otherwise returns [nil][iterum.nil].

    Examples:

        >>> assert Some(2).xor(nil) == Some(2)
        >>> assert nil.xor(Some(100)) == Some(100)
        >>> assert Some(2).xor(Some(100)) == nil
        >>> assert nil.xor(nil) == nil
    """
    return self if isinstance(optb, Nil) else nil

zip(other: Option[U]) -> Option[tuple[T, U]]

Zips self with another option.

If self is Some(s) and other is Some(o), this method returns Some((s, o)). Otherwise, nil is returned.

Examples:

>>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
>>> assert Some(1).zip(nil) == nil
>>> assert nil.zip(nil) == nil
Source code in iterum/_option.py
def zip(self, other: Option[U], /) -> Option[tuple[T, U]]:
    """
    Zips `self` with another option.

    If `self` is `Some(s)` and `other` is `Some(o)`,
    this method returns `Some((s, o))`.
    Otherwise, [nil][iterum.nil] is returned.

    Examples:

        >>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
        >>> assert Some(1).zip(nil) == nil
        >>> assert nil.zip(nil) == nil
    """
    return nil if isinstance(other, Nil) else Some((self._value, other._value))

iterum.Nil

Bases: Singleton

Nil has no value.

Examples:

>>> x = Nil()  # Type of "x" is "Nil"
>>> x
nil
>>> x.is_nil()
True

Nil always returns the same object so just use nil instead.

>>> nil is Nil()
True

Likely, the only practical use of the Nil class is for type annotations and calls to isinstance.

Source code in iterum/_option.py
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
class Nil(Singleton):
    """
    [Nil][iterum.Nil] has no value.

    Examples:

        >>> x = Nil()  # Type of "x" is "Nil"
        >>> x
        nil
        >>> x.is_nil()
        True

    [Nil][iterum.Nil] always returns the same object so just use [nil][iterum.nil] instead.

        >>> nil is Nil()
        True

    Likely, the only practical use of the [Nil][iterum.Nil] class is for type annotations and calls to `isinstance`.
    """

    __slots__ = ()

    def __repr__(self) -> str:
        return "nil"

    def __bool__(self) -> Literal[False]:
        return False

    def and_(self, optb: Option[U], /) -> Nil:
        """
        Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
        returns optb.

        Arguments passed to [and_][iterum.Nil.and_] are eagerly evaluated; if
        you are passing the result of a function call, it is recommended to use
        [and_then][iterum.Nil.and_then], which is lazily evaluated.

        Examples:

            >>> assert Some(2).and_(nil) == nil
            >>> assert nil.and_(Some("foo")) == nil
            >>> assert Some(2).and_(Some("foo")) == Some("foo")
            >>> assert nil.and_(nil) == nil

        Note: because `and` is a keyword, this method is called `and_` instead.
        """
        # 'and' is a keyword, so instead we use 'and_'
        return self

    def and_then(self, f: Callable[[Any], Option[U]], /) -> Nil:
        """
        Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
        calls `f` with the wrapped value and returns the result.

        Examples:

            >>> MAX_U32 = (1 << 32) - 1
            >>> def checked_sq_u32(x: int) -> Option[int]:
            ...     sq = x * x
            ...     if sq > MAX_U32:
            ...         return nil
            ...     return Some(sq)
            ...
            >>> assert Some(2).and_then(checked_sq_u32) == Some(4)
            >>> assert Some(1_000_000).and_then(checked_sq_u32) == nil
            >>> assert nil.and_then(checked_sq_u32) == nil
        """
        return self

    def expect(self, msg: str, /) -> NoReturn:
        """
        Returns the contained [Some][iterum.Some] value, consuming the self value.

        Examples:

            >>> x = Some("value")
            >>> assert x.expect("fruits are healthy") == "value"

            >>> try:
            ...     nil.expect("fruits are healthy")
            ... except ExpectNilError as ex:
            ...     print(ex)
            ...
            fruits are healthy

        Raises:
            ExpectNilError: if the value is a [nil][iterum.nil] with a custom
                panic message provided by msg.
        """
        raise ExpectNilError(msg)

    def filter(self, predicate: Callable[[Any], object], /) -> Nil:
        """
        Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
        calls `predicate` with the wrapped value and returns:

            - [Some(value)][iterum.Some] if the predicate returns `True`
            - [nil][iterum.nil] if the predicate returns `False`

        Examples:

            >>> assert nil.filter(lambda x: x % 2 == 0) == nil
            >>> assert Some(3).filter(lambda x: x % 2 == 0) == nil
            >>> assert Some(4).filter(lambda x: x % 2 == 0) == Some(4)
        """
        return self

    def flatten(self) -> Nil:
        """
        Converts from `Option[Option[T]]` to `Option[T]`.

        Examples:

            >>> assert Some(Some(6)).flatten() == Some(6)
            >>> assert Some(nil).flatten() == nil
            >>> assert nil.flatten() == nil
        """
        return self

    def get_or_insert(self, value: T, /) -> Swap[Some[T], T]:
        """
        Inserts value into the option if it is [nil][iterum.nil], then returns a
        tuple of the resulting option and the returned value.

        See also [insert][iterum.Nil.insert], which updates the value even if
        the option already contains a value.

        Examples:

            >>> opt = nil
            >>> opt, value = opt.get_or_insert(5)
            >>> assert value == 5
            >>> assert opt == Some(5)

            >>> opt = Some(3)
            >>> opt, value = opt.get_or_insert(5)
            >>> assert value == 3
            >>> assert opt == Some(3)

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> assert Some(10).get_or_insert(5).returned == 10
            >>> assert nil.get_or_insert(5).returned == 5

            >>> assert Some(10).get_or_insert(5).inserted == Some(10)
            >>> assert nil.get_or_insert(5).inserted == Some(5)
        """
        return Swap(Some(value), value)

    def get_or_insert_with(self, f: Callable[[], T], /) -> Swap[Some[T], T]:
        """
        Inserts a value computed from `f` into the option if it is
        [nil][iterum.nil], then returns a tuple of the resulting option and the
        returned value.

        Examples:

            >>> opt = nil
            >>> opt, value = opt.get_or_insert_with(lambda: 5)
            >>> assert value == 5
            >>> assert opt == Some(5)

            >>> opt = Some(3)
            >>> opt, value = opt.get_or_insert_with(lambda: 5)
            >>> assert value == 3
            >>> assert opt == Some(3)

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(10).get_or_insert_with(lambda: 5)
            >>> assert swap.inserted == Some(10)
            >>> assert swap.returned == 10

            >>> swap = nil.get_or_insert_with(lambda: 5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == 5
        """
        return Swap(Some(value := f()), value)

    def insert(self, value: T, /) -> Swap[Some[T], T]:
        """
        Inserts value into the option, then returns a tuple of the resulting
        option and the returned value.

        If the option already contains a value, the old value is dropped.

        See also [get_or_insert][iterum.Nil.get_or_insert], which doesn’t
        update the value if the option already contains a value.

        Examples:

            >>> opt = nil
            >>> opt, value = opt.insert(1)
            >>> assert value == 1
            >>> assert opt == Some(1)

            >>> opt = Some(3)
            >>> opt, value = opt.insert(1)
            >>> assert value == 1
            >>> assert opt == Some(1)

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(10).insert(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == 5

            >>> swap = nil.insert(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == 5
        """
        return Swap(Some(value), value)

    def is_nil(self) -> Literal[True]:
        """
        Returns `True` if the option is a [nil][iterum.nil] value.

        Examples:

            >>> assert Some(2).is_nil() is False
            >>> assert nil.is_nil() is True
        """
        return True

    def is_some(self) -> Literal[False]:
        """
        Returns `True` if the option is a Some value.

        Examples:

            >>> assert Some(2).is_some() is True
            >>> assert nil.is_some() is False
        """
        return False

    def is_some_and(self, f: Callable[[Any], object]) -> Literal[False]:
        """
        Returns `True` if the option is a [Some][iterum.Some] and the value
        inside of it matches a predicate.

        Examples:

            >>> assert Some(2).is_some_and(lambda x: x > 1) is True
            >>> assert Some(0).is_some_and(lambda x: x > 1) is False
            >>> assert nil.is_some_and(lambda x: x > 1) is False
        """
        return False

    def iter(self) -> iterum[Any]:
        """
        Returns an iterator over the possibly contained value.

        Examples:

            >>> assert Some(4).iter().next() == Some(4)
            >>> assert nil.iter().next() == nil
        """
        from ._iterum import iterum

        return iterum([])

    def map(self, f: Callable[[Any], Any], /) -> Nil:
        """
        Maps an [Option[T]][iterum.Option] to [Option[U]][iterum.Option] by
        applying a function to a contained value (if [Some][iterum.Some]) or
        returns [nil][iterum.nil] (if [Nil][iterum.Nil]).

        Examples:

            >>> assert Some("Hello, World!").map(len) == Some(13)
            >>> assert nil.map(len) == nil
        """
        return self

    def map_or(self, default: U, f: Callable[[Any], U], /) -> U:
        """
        Returns the provided default result (if [nil][iterum.nil]), or applies a
        function to the contained value (if any).

        Arguments passed to [map_or][iterum.Nil.map_or] are eagerly evaluated;
        if you are passing the result of a function call, it is recommended to
        use [map_or_else][iterum.Nil.map_or_else], which is lazily evaluated.

        Examples:

            >>> assert Some("foo").map_or(42, len) == 3
            >>> assert nil.map_or(42, len) == 42
        """
        return default

    def map_or_else(self, default: Callable[[], U], f: Callable[[Any], U], /) -> U:
        """
        Computes a default function result (if [nil][iterum.nil]), or applies a
        different function to the contained value (if any).

        Examples:

            >>> k = 21
            >>> assert Some("foo").map_or_else(lambda: 2 * k, len) == 3
            >>> assert nil.map_or_else(lambda: 2 * k, len) == 42
        """
        return default()

    def ok_or(self, err: Exception, /) -> NoReturn:
        """
        Unwraps the option returning the value if [Some][iterum.Some] or raises
        the provided exception if [nil][iterum.nil].

        Arguments passed to [ok_or][iterum.Nil.ok_or] are eagerly evaluated; if
        you are passing the result of a function call, it is recommended to use
        [ok_or_else][iterum.Nil.ok_or_else], which is lazily evaluated.

        Examples:

            >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

            >>> try:
            ...     nil.ok_or(RuntimeError("oh no!"))
            ... except RuntimeError as ex:
            ...     print(ex)
            ...
            oh no!
        """
        raise err

    def ok_or_else(self, err: Callable[[], Exception], /) -> NoReturn:
        """
        Unwraps the option returning the value if [Some][iterum.Some] or raises
        the exception returned by the provided callable if [nil][iterum.nil].

        Examples:

            >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

            >>> try:
            ...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
            ... except AssertionError as ex:
            ...     print(ex)
            ...
            oopsy!
        """
        raise err()

    def or_(self, optb: O, /) -> O:
        """
        Returns the option if it contains a value, otherwise returns optb.

        Arguments passed to [or_][iterum.Nil.or_] are eagerly evaluated; if you
        are passing the result of a function call, it is recommended to use
        [or_else][iterum.Nil.or_else], which is lazily evaluated.

        Examples:

            >>> assert Some(2).or_(nil) == Some(2)
            >>> assert nil.or_(Some(100)) == Some(100)
            >>> assert Some(2).or_(Some(100)) == Some(2)
            >>> assert nil.or_(nil) == nil

        Note: because `or` is a keyword, this method is called `or_` instead.
        """
        # 'or' is a keyword, so instead we use 'or_'
        return optb

    def or_else(self, f: Callable[[], O], /) -> O:
        """
        Returns the option if it contains a value, otherwise calls `f` and
        returns the result.

        Examples:

            >>> def nobody() -> Option[str]:
            ...     return nil
            ...
            >>> def vikings() -> Option[str]:
            ...     return Some("vikings")
            ...
            >>> assert Some("barbarians").or_else(vikings) == Some("barbarians")
            >>> assert nil.or_else(vikings) == Some("vikings")
            >>> assert nil.or_else(nobody) == nil
        """
        return f()

    def replace(self, value: T, /) -> Swap[Some[T], Nil]:
        """
        Replaces the actual value in the option by the value given in parameter,
        returning a tuple of the resulting option and the returned old value if
        present.

        Examples:

            >>> x = Some(2)
            >>> new, old = x.replace(5)
            >>> assert new == Some(5)
            >>> assert old == Some(2)

            >>> x = nil
            >>> new, old = x.replace(5)
            >>> assert new == Some(5)
            >>> assert old == nil

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(10).replace(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == Some(10)

            >>> swap = nil.replace(5)
            >>> assert swap.inserted == Some(5)
            >>> assert swap.returned == nil
        """
        return Swap(Some(value), nil)

    def take(self) -> Swap[Nil, Nil]:
        """
        Takes the value out of the option, returning a tuple of the resulting
        nil and the old option.

        Examples:

            >>> x = Some(2)
            >>> new, old = x.take()
            >>> assert new == nil
            >>> assert old == Some(2)

            >>> x = nil
            >>> new, old = x.take()
            >>> assert new == nil
            >>> assert old == nil

            Alternatively, access the named attributes of [Swap][iterum.Swap],
            [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

            >>> swap = Some(2).take()
            >>> assert swap.inserted == nil
            >>> assert swap.returned == Some(2)

            >>> swap = nil.take()
            >>> assert swap.inserted == nil
            >>> assert swap.returned == nil
        """
        return Swap(nil, self)

    # transpose ... without a Result concept there isn't any value

    def unwrap(self) -> NoReturn:
        """
        Returns the contained [Some][iterum.Some] value.

        Examples:

            >>> assert Some("air").unwrap() == "air"

            >>> try:
            ...     nil.unwrap()
            ... except UnwrapNilError as ex:
            ...     print("Attempted to unwrap a nil!")
            ...
            Attempted to unwrap a nil!

        Raises:
            UnwrapNilError: if the value is a [nil][iterum.nil].
        """
        raise UnwrapNilError()

    def unwrap_or(self, default: T, /) -> T:
        """
        Returns the contained [Some][iterum.Some] value or a provided default.

        Arguments passed to [unwrap_or][iterum.Nil.unwrap_or] are eagerly
        evaluated; if you are passing the result of a function call, it is
        recommended to use [unwrap_or_else][iterum.Nil.unwrap_or_else], which
        is lazily evaluated.

        Examples:

            >>> assert Some("car").unwrap_or("bike") == "car"
            >>> assert nil.unwrap_or("bike") == "bike"
        """
        return default

    # In order for unwrap_or_default to be implemented we would
    # need to know within nil what type we are supposed to have.
    #
    # If this was known we could come up with reasonable defaults, e.g. 0, {}, [], "", ...
    # note: these also happen to be what constructing the type with no params gives.
    #
    # If I wanted to get real fancy could provide user way to register defaults
    # for their custom types.

    def unwrap_or_else(self, f: Callable[[], T], /) -> T:
        """
        Returns the contained [Some][iterum.Some] value or computes it from a closure.

        Examples:

            >>> k = 10
            >>> assert Some(4).unwrap_or_else(lambda: 2 * k) == 4
            >>> assert nil.unwrap_or_else(lambda: 2 * k) == 20
        """
        return f()

    def unzip(self) -> tuple[Nil, Nil]:
        """
        Unzips an option containing a tuple of two options.

        If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`.
        Otherwise, `(nil, nil)` is returned.

        Examples:

            >>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
            >>> assert nil.unzip() == (nil, nil)
        """
        return (nil, nil)

    @overload
    def xor(self, optb: S, /) -> S:
        ...

    @overload
    def xor(self, optb: Nil, /) -> Nil:
        ...

    def xor(self, optb: O, /) -> O | Nil:
        """
        Returns [Some][iterum.Some] if exactly one of `self`, `optb` is
        [Some][iterum.Some], otherwise returns [nil][iterum.nil].

        Examples:

            >>> assert Some(2).xor(nil) == Some(2)
            >>> assert nil.xor(Some(100)) == Some(100)
            >>> assert Some(2).xor(Some(100)) == nil
            >>> assert nil.xor(nil) == nil
        """
        return nil if isinstance(optb, Nil) else optb

    def zip(self, other: Option[U], /) -> Nil:
        """
        Zips `self` with another option.

        If `self` is `Some(s)` and `other` is `Some(o)`,
        this method returns `Some((s, o))`.
        Otherwise, [nil][iterum.nil] is returned.

        Examples:

            >>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
            >>> assert Some(1).zip(nil) == nil
            >>> assert nil.zip(nil) == nil
        """
        return self

and_(optb: Option[U]) -> Nil

Returns nil if the option is nil, otherwise returns optb.

Arguments passed to and_ are eagerly evaluated; if you are passing the result of a function call, it is recommended to use and_then, which is lazily evaluated.

Examples:

>>> assert Some(2).and_(nil) == nil
>>> assert nil.and_(Some("foo")) == nil
>>> assert Some(2).and_(Some("foo")) == Some("foo")
>>> assert nil.and_(nil) == nil

Note: because and is a keyword, this method is called and_ instead.

Source code in iterum/_option.py
def and_(self, optb: Option[U], /) -> Nil:
    """
    Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
    returns optb.

    Arguments passed to [and_][iterum.Nil.and_] are eagerly evaluated; if
    you are passing the result of a function call, it is recommended to use
    [and_then][iterum.Nil.and_then], which is lazily evaluated.

    Examples:

        >>> assert Some(2).and_(nil) == nil
        >>> assert nil.and_(Some("foo")) == nil
        >>> assert Some(2).and_(Some("foo")) == Some("foo")
        >>> assert nil.and_(nil) == nil

    Note: because `and` is a keyword, this method is called `and_` instead.
    """
    # 'and' is a keyword, so instead we use 'and_'
    return self

and_then(f: Callable[[Any], Option[U]]) -> Nil

Returns nil if the option is nil, otherwise calls f with the wrapped value and returns the result.

Examples:

>>> MAX_U32 = (1 << 32) - 1
>>> def checked_sq_u32(x: int) -> Option[int]:
...     sq = x * x
...     if sq > MAX_U32:
...         return nil
...     return Some(sq)
...
>>> assert Some(2).and_then(checked_sq_u32) == Some(4)
>>> assert Some(1_000_000).and_then(checked_sq_u32) == nil
>>> assert nil.and_then(checked_sq_u32) == nil
Source code in iterum/_option.py
def and_then(self, f: Callable[[Any], Option[U]], /) -> Nil:
    """
    Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
    calls `f` with the wrapped value and returns the result.

    Examples:

        >>> MAX_U32 = (1 << 32) - 1
        >>> def checked_sq_u32(x: int) -> Option[int]:
        ...     sq = x * x
        ...     if sq > MAX_U32:
        ...         return nil
        ...     return Some(sq)
        ...
        >>> assert Some(2).and_then(checked_sq_u32) == Some(4)
        >>> assert Some(1_000_000).and_then(checked_sq_u32) == nil
        >>> assert nil.and_then(checked_sq_u32) == nil
    """
    return self

expect(msg: str) -> NoReturn

Returns the contained Some value, consuming the self value.

Examples:

>>> x = Some("value")
>>> assert x.expect("fruits are healthy") == "value"
>>> try:
...     nil.expect("fruits are healthy")
... except ExpectNilError as ex:
...     print(ex)
...
fruits are healthy

Raises:

Type Description
ExpectNilError

if the value is a nil with a custom panic message provided by msg.

Source code in iterum/_option.py
def expect(self, msg: str, /) -> NoReturn:
    """
    Returns the contained [Some][iterum.Some] value, consuming the self value.

    Examples:

        >>> x = Some("value")
        >>> assert x.expect("fruits are healthy") == "value"

        >>> try:
        ...     nil.expect("fruits are healthy")
        ... except ExpectNilError as ex:
        ...     print(ex)
        ...
        fruits are healthy

    Raises:
        ExpectNilError: if the value is a [nil][iterum.nil] with a custom
            panic message provided by msg.
    """
    raise ExpectNilError(msg)

filter(predicate: Callable[[Any], object]) -> Nil

Returns nil if the option is nil, otherwise calls predicate with the wrapped value and returns:

- [Some(value)][iterum.Some] if the predicate returns `True`
- [nil][iterum.nil] if the predicate returns `False`

Examples:

>>> assert nil.filter(lambda x: x % 2 == 0) == nil
>>> assert Some(3).filter(lambda x: x % 2 == 0) == nil
>>> assert Some(4).filter(lambda x: x % 2 == 0) == Some(4)
Source code in iterum/_option.py
def filter(self, predicate: Callable[[Any], object], /) -> Nil:
    """
    Returns [nil][iterum.nil] if the option is [nil][iterum.nil], otherwise
    calls `predicate` with the wrapped value and returns:

        - [Some(value)][iterum.Some] if the predicate returns `True`
        - [nil][iterum.nil] if the predicate returns `False`

    Examples:

        >>> assert nil.filter(lambda x: x % 2 == 0) == nil
        >>> assert Some(3).filter(lambda x: x % 2 == 0) == nil
        >>> assert Some(4).filter(lambda x: x % 2 == 0) == Some(4)
    """
    return self

flatten() -> Nil

Converts from Option[Option[T]] to Option[T].

Examples:

>>> assert Some(Some(6)).flatten() == Some(6)
>>> assert Some(nil).flatten() == nil
>>> assert nil.flatten() == nil
Source code in iterum/_option.py
def flatten(self) -> Nil:
    """
    Converts from `Option[Option[T]]` to `Option[T]`.

    Examples:

        >>> assert Some(Some(6)).flatten() == Some(6)
        >>> assert Some(nil).flatten() == nil
        >>> assert nil.flatten() == nil
    """
    return self

get_or_insert(value: T) -> Swap[Some[T], T]

Inserts value into the option if it is nil, then returns a tuple of the resulting option and the returned value.

See also insert, which updates the value even if the option already contains a value.

Examples:

>>> opt = nil
>>> opt, value = opt.get_or_insert(5)
>>> assert value == 5
>>> assert opt == Some(5)
>>> opt = Some(3)
>>> opt, value = opt.get_or_insert(5)
>>> assert value == 3
>>> assert opt == Some(3)

Alternatively, access the named attributes of Swap, inserted and returned:

>>> assert Some(10).get_or_insert(5).returned == 10
>>> assert nil.get_or_insert(5).returned == 5
>>> assert Some(10).get_or_insert(5).inserted == Some(10)
>>> assert nil.get_or_insert(5).inserted == Some(5)
Source code in iterum/_option.py
def get_or_insert(self, value: T, /) -> Swap[Some[T], T]:
    """
    Inserts value into the option if it is [nil][iterum.nil], then returns a
    tuple of the resulting option and the returned value.

    See also [insert][iterum.Nil.insert], which updates the value even if
    the option already contains a value.

    Examples:

        >>> opt = nil
        >>> opt, value = opt.get_or_insert(5)
        >>> assert value == 5
        >>> assert opt == Some(5)

        >>> opt = Some(3)
        >>> opt, value = opt.get_or_insert(5)
        >>> assert value == 3
        >>> assert opt == Some(3)

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> assert Some(10).get_or_insert(5).returned == 10
        >>> assert nil.get_or_insert(5).returned == 5

        >>> assert Some(10).get_or_insert(5).inserted == Some(10)
        >>> assert nil.get_or_insert(5).inserted == Some(5)
    """
    return Swap(Some(value), value)

get_or_insert_with(f: Callable[[], T]) -> Swap[Some[T], T]

Inserts a value computed from f into the option if it is nil, then returns a tuple of the resulting option and the returned value.

Examples:

>>> opt = nil
>>> opt, value = opt.get_or_insert_with(lambda: 5)
>>> assert value == 5
>>> assert opt == Some(5)
>>> opt = Some(3)
>>> opt, value = opt.get_or_insert_with(lambda: 5)
>>> assert value == 3
>>> assert opt == Some(3)

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(10).get_or_insert_with(lambda: 5)
>>> assert swap.inserted == Some(10)
>>> assert swap.returned == 10
>>> swap = nil.get_or_insert_with(lambda: 5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == 5
Source code in iterum/_option.py
def get_or_insert_with(self, f: Callable[[], T], /) -> Swap[Some[T], T]:
    """
    Inserts a value computed from `f` into the option if it is
    [nil][iterum.nil], then returns a tuple of the resulting option and the
    returned value.

    Examples:

        >>> opt = nil
        >>> opt, value = opt.get_or_insert_with(lambda: 5)
        >>> assert value == 5
        >>> assert opt == Some(5)

        >>> opt = Some(3)
        >>> opt, value = opt.get_or_insert_with(lambda: 5)
        >>> assert value == 3
        >>> assert opt == Some(3)

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(10).get_or_insert_with(lambda: 5)
        >>> assert swap.inserted == Some(10)
        >>> assert swap.returned == 10

        >>> swap = nil.get_or_insert_with(lambda: 5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5
    """
    return Swap(Some(value := f()), value)

insert(value: T) -> Swap[Some[T], T]

Inserts value into the option, then returns a tuple of the resulting option and the returned value.

If the option already contains a value, the old value is dropped.

See also get_or_insert, which doesn’t update the value if the option already contains a value.

Examples:

>>> opt = nil
>>> opt, value = opt.insert(1)
>>> assert value == 1
>>> assert opt == Some(1)
>>> opt = Some(3)
>>> opt, value = opt.insert(1)
>>> assert value == 1
>>> assert opt == Some(1)

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(10).insert(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == 5
>>> swap = nil.insert(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == 5
Source code in iterum/_option.py
def insert(self, value: T, /) -> Swap[Some[T], T]:
    """
    Inserts value into the option, then returns a tuple of the resulting
    option and the returned value.

    If the option already contains a value, the old value is dropped.

    See also [get_or_insert][iterum.Nil.get_or_insert], which doesn’t
    update the value if the option already contains a value.

    Examples:

        >>> opt = nil
        >>> opt, value = opt.insert(1)
        >>> assert value == 1
        >>> assert opt == Some(1)

        >>> opt = Some(3)
        >>> opt, value = opt.insert(1)
        >>> assert value == 1
        >>> assert opt == Some(1)

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(10).insert(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5

        >>> swap = nil.insert(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5
    """
    return Swap(Some(value), value)

is_nil() -> Literal[True]

Returns True if the option is a nil value.

Examples:

>>> assert Some(2).is_nil() is False
>>> assert nil.is_nil() is True
Source code in iterum/_option.py
def is_nil(self) -> Literal[True]:
    """
    Returns `True` if the option is a [nil][iterum.nil] value.

    Examples:

        >>> assert Some(2).is_nil() is False
        >>> assert nil.is_nil() is True
    """
    return True

is_some() -> Literal[False]

Returns True if the option is a Some value.

Examples:

>>> assert Some(2).is_some() is True
>>> assert nil.is_some() is False
Source code in iterum/_option.py
def is_some(self) -> Literal[False]:
    """
    Returns `True` if the option is a Some value.

    Examples:

        >>> assert Some(2).is_some() is True
        >>> assert nil.is_some() is False
    """
    return False

is_some_and(f: Callable[[Any], object]) -> Literal[False]

Returns True if the option is a Some and the value inside of it matches a predicate.

Examples:

>>> assert Some(2).is_some_and(lambda x: x > 1) is True
>>> assert Some(0).is_some_and(lambda x: x > 1) is False
>>> assert nil.is_some_and(lambda x: x > 1) is False
Source code in iterum/_option.py
def is_some_and(self, f: Callable[[Any], object]) -> Literal[False]:
    """
    Returns `True` if the option is a [Some][iterum.Some] and the value
    inside of it matches a predicate.

    Examples:

        >>> assert Some(2).is_some_and(lambda x: x > 1) is True
        >>> assert Some(0).is_some_and(lambda x: x > 1) is False
        >>> assert nil.is_some_and(lambda x: x > 1) is False
    """
    return False

iter() -> iterum[Any]

Returns an iterator over the possibly contained value.

Examples:

>>> assert Some(4).iter().next() == Some(4)
>>> assert nil.iter().next() == nil
Source code in iterum/_option.py
def iter(self) -> iterum[Any]:
    """
    Returns an iterator over the possibly contained value.

    Examples:

        >>> assert Some(4).iter().next() == Some(4)
        >>> assert nil.iter().next() == nil
    """
    from ._iterum import iterum

    return iterum([])

map(f: Callable[[Any], Any]) -> Nil

Maps an Option[T] to Option[U] by applying a function to a contained value (if Some) or returns nil (if Nil).

Examples:

>>> assert Some("Hello, World!").map(len) == Some(13)
>>> assert nil.map(len) == nil
Source code in iterum/_option.py
def map(self, f: Callable[[Any], Any], /) -> Nil:
    """
    Maps an [Option[T]][iterum.Option] to [Option[U]][iterum.Option] by
    applying a function to a contained value (if [Some][iterum.Some]) or
    returns [nil][iterum.nil] (if [Nil][iterum.Nil]).

    Examples:

        >>> assert Some("Hello, World!").map(len) == Some(13)
        >>> assert nil.map(len) == nil
    """
    return self

map_or(default: U, f: Callable[[Any], U]) -> U

Returns the provided default result (if nil), or applies a function to the contained value (if any).

Arguments passed to map_or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use map_or_else, which is lazily evaluated.

Examples:

>>> assert Some("foo").map_or(42, len) == 3
>>> assert nil.map_or(42, len) == 42
Source code in iterum/_option.py
def map_or(self, default: U, f: Callable[[Any], U], /) -> U:
    """
    Returns the provided default result (if [nil][iterum.nil]), or applies a
    function to the contained value (if any).

    Arguments passed to [map_or][iterum.Nil.map_or] are eagerly evaluated;
    if you are passing the result of a function call, it is recommended to
    use [map_or_else][iterum.Nil.map_or_else], which is lazily evaluated.

    Examples:

        >>> assert Some("foo").map_or(42, len) == 3
        >>> assert nil.map_or(42, len) == 42
    """
    return default

map_or_else(default: Callable[[], U], f: Callable[[Any], U]) -> U

Computes a default function result (if nil), or applies a different function to the contained value (if any).

Examples:

>>> k = 21
>>> assert Some("foo").map_or_else(lambda: 2 * k, len) == 3
>>> assert nil.map_or_else(lambda: 2 * k, len) == 42
Source code in iterum/_option.py
def map_or_else(self, default: Callable[[], U], f: Callable[[Any], U], /) -> U:
    """
    Computes a default function result (if [nil][iterum.nil]), or applies a
    different function to the contained value (if any).

    Examples:

        >>> k = 21
        >>> assert Some("foo").map_or_else(lambda: 2 * k, len) == 3
        >>> assert nil.map_or_else(lambda: 2 * k, len) == 42
    """
    return default()

ok_or(err: Exception) -> NoReturn

Unwraps the option returning the value if Some or raises the provided exception if nil.

Arguments passed to ok_or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use ok_or_else, which is lazily evaluated.

Examples:

>>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"
>>> try:
...     nil.ok_or(RuntimeError("oh no!"))
... except RuntimeError as ex:
...     print(ex)
...
oh no!
Source code in iterum/_option.py
def ok_or(self, err: Exception, /) -> NoReturn:
    """
    Unwraps the option returning the value if [Some][iterum.Some] or raises
    the provided exception if [nil][iterum.nil].

    Arguments passed to [ok_or][iterum.Nil.ok_or] are eagerly evaluated; if
    you are passing the result of a function call, it is recommended to use
    [ok_or_else][iterum.Nil.ok_or_else], which is lazily evaluated.

    Examples:

        >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

        >>> try:
        ...     nil.ok_or(RuntimeError("oh no!"))
        ... except RuntimeError as ex:
        ...     print(ex)
        ...
        oh no!
    """
    raise err

ok_or_else(err: Callable[[], Exception]) -> NoReturn

Unwraps the option returning the value if Some or raises the exception returned by the provided callable if nil.

Examples:

>>> assert Some("foo").ok_or_else(AssertionError) == "foo"
>>> try:
...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
... except AssertionError as ex:
...     print(ex)
...
oopsy!
Source code in iterum/_option.py
def ok_or_else(self, err: Callable[[], Exception], /) -> NoReturn:
    """
    Unwraps the option returning the value if [Some][iterum.Some] or raises
    the exception returned by the provided callable if [nil][iterum.nil].

    Examples:

        >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

        >>> try:
        ...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
        ... except AssertionError as ex:
        ...     print(ex)
        ...
        oopsy!
    """
    raise err()

or_(optb: O) -> O

Returns the option if it contains a value, otherwise returns optb.

Arguments passed to or_ are eagerly evaluated; if you are passing the result of a function call, it is recommended to use or_else, which is lazily evaluated.

Examples:

>>> assert Some(2).or_(nil) == Some(2)
>>> assert nil.or_(Some(100)) == Some(100)
>>> assert Some(2).or_(Some(100)) == Some(2)
>>> assert nil.or_(nil) == nil

Note: because or is a keyword, this method is called or_ instead.

Source code in iterum/_option.py
def or_(self, optb: O, /) -> O:
    """
    Returns the option if it contains a value, otherwise returns optb.

    Arguments passed to [or_][iterum.Nil.or_] are eagerly evaluated; if you
    are passing the result of a function call, it is recommended to use
    [or_else][iterum.Nil.or_else], which is lazily evaluated.

    Examples:

        >>> assert Some(2).or_(nil) == Some(2)
        >>> assert nil.or_(Some(100)) == Some(100)
        >>> assert Some(2).or_(Some(100)) == Some(2)
        >>> assert nil.or_(nil) == nil

    Note: because `or` is a keyword, this method is called `or_` instead.
    """
    # 'or' is a keyword, so instead we use 'or_'
    return optb

or_else(f: Callable[[], O]) -> O

Returns the option if it contains a value, otherwise calls f and returns the result.

Examples:

>>> def nobody() -> Option[str]:
...     return nil
...
>>> def vikings() -> Option[str]:
...     return Some("vikings")
...
>>> assert Some("barbarians").or_else(vikings) == Some("barbarians")
>>> assert nil.or_else(vikings) == Some("vikings")
>>> assert nil.or_else(nobody) == nil
Source code in iterum/_option.py
def or_else(self, f: Callable[[], O], /) -> O:
    """
    Returns the option if it contains a value, otherwise calls `f` and
    returns the result.

    Examples:

        >>> def nobody() -> Option[str]:
        ...     return nil
        ...
        >>> def vikings() -> Option[str]:
        ...     return Some("vikings")
        ...
        >>> assert Some("barbarians").or_else(vikings) == Some("barbarians")
        >>> assert nil.or_else(vikings) == Some("vikings")
        >>> assert nil.or_else(nobody) == nil
    """
    return f()

replace(value: T) -> Swap[Some[T], Nil]

Replaces the actual value in the option by the value given in parameter, returning a tuple of the resulting option and the returned old value if present.

Examples:

>>> x = Some(2)
>>> new, old = x.replace(5)
>>> assert new == Some(5)
>>> assert old == Some(2)
>>> x = nil
>>> new, old = x.replace(5)
>>> assert new == Some(5)
>>> assert old == nil

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(10).replace(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == Some(10)
>>> swap = nil.replace(5)
>>> assert swap.inserted == Some(5)
>>> assert swap.returned == nil
Source code in iterum/_option.py
def replace(self, value: T, /) -> Swap[Some[T], Nil]:
    """
    Replaces the actual value in the option by the value given in parameter,
    returning a tuple of the resulting option and the returned old value if
    present.

    Examples:

        >>> x = Some(2)
        >>> new, old = x.replace(5)
        >>> assert new == Some(5)
        >>> assert old == Some(2)

        >>> x = nil
        >>> new, old = x.replace(5)
        >>> assert new == Some(5)
        >>> assert old == nil

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(10).replace(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == Some(10)

        >>> swap = nil.replace(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == nil
    """
    return Swap(Some(value), nil)

take() -> Swap[Nil, Nil]

Takes the value out of the option, returning a tuple of the resulting nil and the old option.

Examples:

>>> x = Some(2)
>>> new, old = x.take()
>>> assert new == nil
>>> assert old == Some(2)
>>> x = nil
>>> new, old = x.take()
>>> assert new == nil
>>> assert old == nil

Alternatively, access the named attributes of Swap, inserted and returned:

>>> swap = Some(2).take()
>>> assert swap.inserted == nil
>>> assert swap.returned == Some(2)
>>> swap = nil.take()
>>> assert swap.inserted == nil
>>> assert swap.returned == nil
Source code in iterum/_option.py
def take(self) -> Swap[Nil, Nil]:
    """
    Takes the value out of the option, returning a tuple of the resulting
    nil and the old option.

    Examples:

        >>> x = Some(2)
        >>> new, old = x.take()
        >>> assert new == nil
        >>> assert old == Some(2)

        >>> x = nil
        >>> new, old = x.take()
        >>> assert new == nil
        >>> assert old == nil

        Alternatively, access the named attributes of [Swap][iterum.Swap],
        [inserted][iterum.Swap.inserted] and [returned][iterum.Swap.returned]:

        >>> swap = Some(2).take()
        >>> assert swap.inserted == nil
        >>> assert swap.returned == Some(2)

        >>> swap = nil.take()
        >>> assert swap.inserted == nil
        >>> assert swap.returned == nil
    """
    return Swap(nil, self)

unwrap() -> NoReturn

Returns the contained Some value.

Examples:

>>> assert Some("air").unwrap() == "air"
>>> try:
...     nil.unwrap()
... except UnwrapNilError as ex:
...     print("Attempted to unwrap a nil!")
...
Attempted to unwrap a nil!

Raises:

Type Description
UnwrapNilError

if the value is a nil.

Source code in iterum/_option.py
def unwrap(self) -> NoReturn:
    """
    Returns the contained [Some][iterum.Some] value.

    Examples:

        >>> assert Some("air").unwrap() == "air"

        >>> try:
        ...     nil.unwrap()
        ... except UnwrapNilError as ex:
        ...     print("Attempted to unwrap a nil!")
        ...
        Attempted to unwrap a nil!

    Raises:
        UnwrapNilError: if the value is a [nil][iterum.nil].
    """
    raise UnwrapNilError()

unwrap_or(default: T) -> T

Returns the contained Some value or a provided default.

Arguments passed to unwrap_or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use unwrap_or_else, which is lazily evaluated.

Examples:

>>> assert Some("car").unwrap_or("bike") == "car"
>>> assert nil.unwrap_or("bike") == "bike"
Source code in iterum/_option.py
def unwrap_or(self, default: T, /) -> T:
    """
    Returns the contained [Some][iterum.Some] value or a provided default.

    Arguments passed to [unwrap_or][iterum.Nil.unwrap_or] are eagerly
    evaluated; if you are passing the result of a function call, it is
    recommended to use [unwrap_or_else][iterum.Nil.unwrap_or_else], which
    is lazily evaluated.

    Examples:

        >>> assert Some("car").unwrap_or("bike") == "car"
        >>> assert nil.unwrap_or("bike") == "bike"
    """
    return default

unwrap_or_else(f: Callable[[], T]) -> T

Returns the contained Some value or computes it from a closure.

Examples:

>>> k = 10
>>> assert Some(4).unwrap_or_else(lambda: 2 * k) == 4
>>> assert nil.unwrap_or_else(lambda: 2 * k) == 20
Source code in iterum/_option.py
def unwrap_or_else(self, f: Callable[[], T], /) -> T:
    """
    Returns the contained [Some][iterum.Some] value or computes it from a closure.

    Examples:

        >>> k = 10
        >>> assert Some(4).unwrap_or_else(lambda: 2 * k) == 4
        >>> assert nil.unwrap_or_else(lambda: 2 * k) == 20
    """
    return f()

unzip() -> tuple[Nil, Nil]

Unzips an option containing a tuple of two options.

If self is Some((a, b)) this method returns (Some(a), Some(b)). Otherwise, (nil, nil) is returned.

Examples:

>>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
>>> assert nil.unzip() == (nil, nil)
Source code in iterum/_option.py
def unzip(self) -> tuple[Nil, Nil]:
    """
    Unzips an option containing a tuple of two options.

    If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`.
    Otherwise, `(nil, nil)` is returned.

    Examples:

        >>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
        >>> assert nil.unzip() == (nil, nil)
    """
    return (nil, nil)

xor(optb: O) -> O | Nil

Returns Some if exactly one of self, optb is Some, otherwise returns nil.

Examples:

>>> assert Some(2).xor(nil) == Some(2)
>>> assert nil.xor(Some(100)) == Some(100)
>>> assert Some(2).xor(Some(100)) == nil
>>> assert nil.xor(nil) == nil
Source code in iterum/_option.py
def xor(self, optb: O, /) -> O | Nil:
    """
    Returns [Some][iterum.Some] if exactly one of `self`, `optb` is
    [Some][iterum.Some], otherwise returns [nil][iterum.nil].

    Examples:

        >>> assert Some(2).xor(nil) == Some(2)
        >>> assert nil.xor(Some(100)) == Some(100)
        >>> assert Some(2).xor(Some(100)) == nil
        >>> assert nil.xor(nil) == nil
    """
    return nil if isinstance(optb, Nil) else optb

zip(other: Option[U]) -> Nil

Zips self with another option.

If self is Some(s) and other is Some(o), this method returns Some((s, o)). Otherwise, nil is returned.

Examples:

>>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
>>> assert Some(1).zip(nil) == nil
>>> assert nil.zip(nil) == nil
Source code in iterum/_option.py
def zip(self, other: Option[U], /) -> Nil:
    """
    Zips `self` with another option.

    If `self` is `Some(s)` and `other` is `Some(o)`,
    this method returns `Some((s, o))`.
    Otherwise, [nil][iterum.nil] is returned.

    Examples:

        >>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
        >>> assert Some(1).zip(nil) == nil
        >>> assert nil.zip(nil) == nil
    """
    return self

iterum.nil = Nil() module-attribute

Instance of type Nil. See Nil for more details.

iterum.ExpectNilError

Bases: RuntimeError

Exception raised when nil.expect is called.

Source code in iterum/_option.py
class ExpectNilError(RuntimeError):
    """
    Exception raised when [nil.expect][iterum.Nil.expect] is called.
    """

    def __init__(self, msg: str = "Expected some but option is nil") -> None:
        super().__init__(msg)

iterum.UnwrapNilError

Bases: RuntimeError

Exception raised when nil.unwrap is called.

Source code in iterum/_option.py
class UnwrapNilError(RuntimeError):
    """
    Exception raised when [nil.unwrap][iterum.Nil.unwrap] is called.
    """

    def __init__(self, msg: str = "Attempted to unwrap nil") -> None:
        super().__init__(msg)


Other


iterum.State dataclass

Bases: Generic[T]

Simple class which holds some mutable state.

Source code in iterum/_iterum.py
@dataclass
class State(Generic[T]):
    """
    Simple class which holds some mutable state.
    """

    value: T
    """
    current value of the state
    """

value: T instance-attribute

current value of the state

iterum.Swap

Bases: NamedTuple, Generic[T, U]

Used for various 'swapping' operations on Option.

Source code in iterum/_option.py
class Swap(NamedTuple, Generic[T, U]):
    """
    Used for various 'swapping' operations on [Option][iterum.Option].
    """

    inserted: T
    """
    Value inserted into an option
    """

    returned: U
    """
    Value returned from an option
    """

inserted: T instance-attribute

Value inserted into an option

returned: U instance-attribute

Value returned from an option

iterum.Ordering

Bases: Enum

An Ordering is the result of a comparison between two values.

Source code in iterum/_ordering.py
@unique
class Ordering(Enum):
    """
    An [Ordering][iterum.Ordering] is the result of a comparison between
    two values.
    """

    Less = create_singleton("Less")
    """
    An ordering where a compared value is less than another.
    """

    Equal = create_singleton("Equal")
    """
    An ordering where a compared value is equal to another.
    """

    Greater = create_singleton("Greater")
    """
    An ordering where a compared value is greater than another.
    """

    @staticmethod
    def cmp(lhs, rhs, /) -> Ordering:
        """
        Compare two values.

        Examples:

            >>> Ordering.cmp(1, 2)
            Ordering.Less
            >>> Ordering.cmp(1, 1)
            Ordering.Equal
            >>> Ordering.cmp(2, 1)
            Ordering.Greater

            A `TypeError` will be raised if the two objects are not comparable:
            >>> try:
            ...     Ordering.cmp(1, "two")
            ... except TypeError as ex:
            ...     print(f"exception received: {ex}")
            ...
            exception received: '>' not supported between instances of 'int' and 'str'
        """

        if lhs == rhs:
            return Ordering.Equal
        if lhs > rhs:
            return Ordering.Greater
        if lhs < rhs:
            return Ordering.Less
        raise ValueError(f"Unable to compare {lhs!r} with {rhs!r}")

    def __repr__(self) -> str:
        return f"{type(self).__name__}.{self.name}"

Less = create_singleton('Less') class-attribute instance-attribute

An ordering where a compared value is less than another.

Equal = create_singleton('Equal') class-attribute instance-attribute

An ordering where a compared value is equal to another.

Greater = create_singleton('Greater') class-attribute instance-attribute

An ordering where a compared value is greater than another.

cmp(lhs, rhs) -> Ordering staticmethod

Compare two values.

Examples:

>>> Ordering.cmp(1, 2)
Ordering.Less
>>> Ordering.cmp(1, 1)
Ordering.Equal
>>> Ordering.cmp(2, 1)
Ordering.Greater

A TypeError will be raised if the two objects are not comparable:

>>> try:
...     Ordering.cmp(1, "two")
... except TypeError as ex:
...     print(f"exception received: {ex}")
...
exception received: '>' not supported between instances of 'int' and 'str'
Source code in iterum/_ordering.py
@staticmethod
def cmp(lhs, rhs, /) -> Ordering:
    """
    Compare two values.

    Examples:

        >>> Ordering.cmp(1, 2)
        Ordering.Less
        >>> Ordering.cmp(1, 1)
        Ordering.Equal
        >>> Ordering.cmp(2, 1)
        Ordering.Greater

        A `TypeError` will be raised if the two objects are not comparable:
        >>> try:
        ...     Ordering.cmp(1, "two")
        ... except TypeError as ex:
        ...     print(f"exception received: {ex}")
        ...
        exception received: '>' not supported between instances of 'int' and 'str'
    """

    if lhs == rhs:
        return Ordering.Equal
    if lhs > rhs:
        return Ordering.Greater
    if lhs < rhs:
        return Ordering.Less
    raise ValueError(f"Unable to compare {lhs!r} with {rhs!r}")

iterum.Chain

Bases: _IterumAdapter[T_co]

Source code in iterum/_iterum.py
class Chain(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

    def __init__(self, *__iterables: Iterable[T_co]) -> None:
        self._iter = itertools.chain(*__iterables)

iterum.Cycle

Bases: _IterumAdapter[T_co]

Source code in iterum/_iterum.py
class Cycle(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

    def __init__(self, __iterable: Iterable[T_co]) -> None:
        self._iter = itertools.cycle(__iterable)

iterum.Enumerate

Bases: _IterumAdapter[tuple[int, T_co]]

Source code in iterum/_iterum.py
class Enumerate(_IterumAdapter[tuple[int, T_co]]):
    __slots__ = ("_iter",)

    def __init__(self, __iterable: Iterable[T_co], /) -> None:
        self._iter = builtins.enumerate(__iterable)

iterum.Filter

Bases: _IterumAdapter[T_co]

Source code in iterum/_iterum.py
class Filter(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

    def __init__(
        self, __iterable: Iterable[T_co], predicate: Callable[[T_co], object], /
    ) -> None:
        self._iter = builtins.filter(predicate, __iterable)

iterum.FlatMap

Bases: _IterumAdapter[T_co]

Source code in iterum/_iterum.py
class FlatMap(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

    def __init__(
        self, __iterable: Iterable[U], f: Callable[[U], Iterable[T_co]], /
    ) -> None:
        self._iter = iterum(__iterable).map(f).flatten()

iterum.FilterMap

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class FilterMap(Iterum[T_co]):
    __slots__ = ("_iter", "_predicate")

    def __init__(
        self, __iterable: Iterable[U], predicate: Callable[[U], Option[T_co]], /
    ) -> None:
        self._iter = iterum(__iterable)
        self._predicate = predicate

    def next(self) -> Option[T_co]:
        while True:
            x = self._iter.next()
            if x.is_nil():
                return nil

            r = self._predicate(x.unwrap())
            if r.is_some():
                return r

iterum.Flatten

Bases: _IterumAdapter[T_co]

Source code in iterum/_iterum.py
class Flatten(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

    def __init__(self, __iterable: Iterable[Iterable[T_co]], /) -> None:
        self._iter = iter(y for x in __iterable for y in x)

iterum.Fuse

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class Fuse(Iterum[T_co]):
    __slots__ = ("_iter", "_fuse")

    def __init__(self, __iterable: Iterable[T_co]) -> None:
        self._iter = iterum(__iterable)
        self._fuse = True

    def next(self) -> Option[T_co]:
        if not self._fuse:
            return nil

        nxt = self._iter.next()
        if nxt.is_nil():
            self._fuse = False
            return nil

        return nxt

iterum.Inspect

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class Inspect(Iterum[T_co]):
    __slots__ = ("_iter", "_f")

    def __init__(
        self, __iterable: Iterable[T_co], f: Callable[[T_co], object], /
    ) -> None:
        self._iter = iterum(__iterable)
        self._f = f

    def next(self) -> Option[T_co]:
        nxt = self._iter.next()
        nxt.map(self._f)
        return nxt

iterum.Map

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class Map(Iterum[T_co]):
    __slots__ = ("_iter", "_f")

    def __init__(self, __iterable: Iterable[U], f: Callable[[U], T_co], /) -> None:
        self._iter = iterum(__iterable)
        self._f = f

    def next(self) -> Option[T_co]:
        return self._iter.next().map(self._f)

iterum.MapWhile

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class MapWhile(Iterum[T_co]):
    __slots__ = ("_iter", "_predicate", "_fuse")

    def __init__(
        self, __iterable: Iterable[U], predicate: Callable[[U], Option[T_co]], /
    ) -> None:
        self._iter = iterum(__iterable)
        self._predicate = predicate
        self._fuse = True

    def next(self) -> Option[T_co]:
        if not self._fuse:
            return nil

        r = self._iter.next().map(self._predicate).flatten()
        if r.is_nil():
            self._fuse = False

        return r

iterum.Peekable

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class Peekable(Iterum[T_co]):
    __slots__ = ("_iter", "_peek")

    def __init__(self, __iterable: Iterable[T_co], /) -> None:
        self._iter = iterum(__iterable)
        self._peek: Option[T_co] | NotSetType = NotSet

    def next(self) -> Option[T_co]:
        if isinstance(self._peek, NotSetType):
            return self._iter.next()
        elif self._peek is nil:
            return nil
        else:
            nxt, self._peek = self._peek, NotSet
            return nxt

    @property
    def peek(self) -> Option[T_co]:
        if isinstance(self._peek, NotSetType):
            self._peek = self.next()

        return self._peek

    @peek.setter
    def peek(self, value: T_co) -> None:  # type: ignore | reason: still need to constrain input param type
        if self.peek.is_nil():
            raise IndexError("Cannot set peek value past end of the iterum")

        self._peek = Some(value)

iterum.Rev

Bases: Diterum[T_co]

Implements a Diterum interface that wraps a diterum object and swaps calls to next with next_back and vice versa.

Source code in iterum/_diterum.py
class Rev(Diterum[T_co]):
    """
    Implements a [Diterum][iterum.Diterum] interface that wraps
    a [diterum][iterum.diterum] object and swaps calls to
    [next][iterum.Diterum.next_back] with [next_back][iterum.Iterum.next]
    and vice versa.
    """

    __slots__ = ("_x",)

    def __init__(self, __x: Diterum[T_co] | Sequence[T_co]) -> None:
        self._x = __x if isinstance(__x, Diterum) else diterum(__x)

    def next(self) -> Option[T_co]:
        return self._x.next_back()

    def next_back(self) -> Option[T_co]:
        return self._x.next()

    def len(self) -> int:
        return self._x.len()

iterum.Scan

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class Scan(Iterum[T_co]):
    __slots__ = ("_iter", "_state", "_f")

    def __init__(
        self,
        __iterable: Iterable[U],
        init: V,
        f: Callable[[State[V], U], Option[T_co]],
        /,
    ):
        self._iter = iterum(__iterable)
        self._state = State(init)
        self._f = f

    def next(self) -> Option[T_co]:
        return self._iter.next().map(lambda val: self._f(self._state, val)).flatten()

iterum.Skip

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class Skip(Iterum[T_co]):
    __slots__ = ("_iter", "_n")

    def __init__(
        self,
        __iterable: Iterable[T_co],
        n: int,
        /,
    ) -> None:
        self._iter = iterum(__iterable)
        self._n = n

    def next(self) -> Option[T_co]:
        if self._n:
            self._iter.nth(self._n - 1)
            self._n = 0

        return self._iter.next()

iterum.SkipWhile

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class SkipWhile(Iterum[T_co]):
    __slots__ = ("_iter", "_predicate", "_fuse")

    def __init__(
        self,
        __iterable: Iterable[T_co],
        predicate: Callable[[T_co], object],
        /,
    ) -> None:
        self._iter = iterum(__iterable)
        self._predicate = predicate
        self._fuse = True

    def next(self) -> Option[T_co]:
        if not self._fuse:
            return self._iter.next()

        nxt = nil
        while self._fuse:
            nxt = self._iter.next()
            self._fuse = nxt.is_some_and(self._predicate)

        return nxt

iterum.StepBy

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class StepBy(Iterum[T_co]):
    __slots__ = ("_iter", "_step")

    def __init__(self, __iterable: Iterable[T_co], step: int, /) -> None:
        if step <= 0:
            raise ValueError(f"Step must be positive, provided: {step}")

        self._iter = iterum(__iterable).enumerate()
        self._step = step

    def next(self) -> Option[T_co]:
        idx, nxt = self._iter.next().unzip()
        while nxt.is_some() and idx.is_some_and(lambda idx: idx % self._step):
            idx, nxt = self._iter.next().unzip()

        return nxt

iterum.Take

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class Take(Iterum[T_co]):
    __slots__ = ("_iter", "_max", "_idx")

    def __init__(self, __iterable: Iterable[T_co], n: int, /) -> None:
        self._iter = iterum(__iterable)
        self._max = n
        self._idx = 0

    def next(self) -> Option[T_co]:
        if self._idx >= self._max:
            return nil

        self._idx += 1
        return self._iter.next()

iterum.TakeWhile

Bases: Iterum[T_co]

Source code in iterum/_iterum.py
class TakeWhile(Iterum[T_co]):
    __slots__ = ("_iter", "_predicate")

    def __init__(
        self, __iterable: Iterable[T_co], predicate: Callable[[T_co], object], /
    ) -> None:
        self._iter = iterum(__iterable)
        self._predicate = predicate

    def next(self) -> Option[T_co]:
        nxt = self._iter.next()
        if nxt.is_some_and(self._predicate):
            return nxt
        return nil

iterum.Zip

Bases: _IterumAdapter[tuple[U, V]]

Source code in iterum/_iterum.py
class Zip(_IterumAdapter[tuple[U, V]]):
    __slots__ = ("_iter",)

    def __init__(self, __iterable: Iterable[U], other: Iterable[V], /) -> None:
        self._iter = zip(__iterable, other)

iterum.Seq

Bases: Diterum[int]

Source code in iterum/_seq.py
class Seq(Diterum[int]):
    __slots__ = ("_front", "_back", "_step", "_dir")

    def __init__(self, *, start: int, end: int, step: int) -> None:
        self._front = start
        self._back = _compute_back(start, end, step)
        self._step = step
        self._dir = _sign(step)

    def next(self) -> Option[int]:
        if self._dir * (self._back - self._front) < 0:
            return nil

        nxt = Some(self._front)
        self._front += self._step
        return nxt

    def next_back(self) -> Option[int]:
        if self._dir * (self._back - self._front) < 0:
            return nil

        nxt_bk = Some(self._back)
        self._back -= self._step
        return nxt_bk

    def len(self) -> int:
        if self._dir * (self._back - self._front) < 0:
            return 0

        return (self._back + self._step - self._front) // self._step

    def __repr__(self) -> str:
        return (
            f"{type(self).__name__}("
            f"start={self._front}"
            f", end={self._back + self._step}"
            f", step={self._step}"
            ")"
        )

    def __bool__(self) -> bool:
        return self.len() != 0

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Seq):
            return NotImplemented
        return (
            (self._front == other._front)
            and (self._back == other._back)
            and (self._step == other._step)
        )

iterum.InfSeq

Bases: Iterum[int]

Source code in iterum/_seq.py
class InfSeq(Iterum[int]):
    __slots__ = ("_front", "_step")

    def __init__(self, *, start: int, step: int) -> None:
        self._front = start
        self._step = step

    def next(self) -> Option[int]:
        nxt = Some(self._front)
        self._front += self._step
        return nxt

    def __repr__(self) -> str:
        return f"{type(self).__name__}(start={self._front}, step={self._step})"

    def __bool__(self) -> bool:
        return True

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, InfSeq):
            return NotImplemented
        return (self._front == other._front) and (self._step == other._step)