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 src/iterum/_iterum.py
class iterum(Iterum[T_co]):
    """
    Implements an [Iterum][iterum.Iterum] interface from an iterable object.

    **Examples:**

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

    ```

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

    ```

    ```python
    >>> 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)

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

        **Examples:**

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

        ```
        """
        return _try_next(self._iter)

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(__iterable: Iterable[T_co]) -> None
Source code in src/iterum/_iterum.py
def __init__(self, __iterable: Iterable[T_co], /) -> None:
    self._iter = iter(__iterable)

next

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 src/iterum/_iterum.py
@override
def next(self) -> Option[T_co]:
    """
    Returns the next value in the iterable if present, otherwise [nil][iterum.nil].

    **Examples:**

    ```python
    >>> 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 src/iterum/_iterum.py
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  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
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
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:**

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

        ```

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

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

        ```

        ... and then [nil][iterum.nil] once it's over.

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

        ```

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

        ```python
        >>> 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

    @override
    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:**

        ```python
        >>> 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`:

        ```python
        >>> 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:**

        ```python
        >>> 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`:

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

        ```

        itr still has more elements.

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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[U, V](
        self: Iterum[tuple[U, V]], container: type[dict], /
    ) -> dict[U, V]: ...

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

    def collect[U](  # 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:**

        ```python
        >>> 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`

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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[U](
        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:**

        ```python
        >>> 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:**

        ```python
        >>> 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`:

        ```python
        >>> 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[U](self, predicate: Callable[[T_co], Option[U]], /) -> Option[U]:
        """
        Applies function to the elements of iterum and returns the first
        non-nil result.

        **Examples:**

        ```python
        >>> 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[U](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:**

        ```python
        >>> words = ["alpha", "beta", "gamma"]
        >>> merged = iterum(words).flat_map(iterum).collect("".join)
        >>> assert merged == "alphabetagamma"

        ```
        """
        return FlatMap(self, f)

    def flatten[U](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:**

        ```python
        >>> 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:

        ```python
        >>> words = ["alpha", "beta", "gamma"]
        >>> merged = iterum(words).map(iterum).flatten().collect("".join)
        >>> assert merged == "alphabetagamma"

        ```
        """
        return Flatten(self)

    def fold[U](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:**

        ```python
        >>> 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.


        ??? note "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:**

        ```python
        >>> 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:**

        ```python
        >>> 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()
        ...

        ```

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

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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[U](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:**

        ```python
        >>> 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[U](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:**

        ```python
        >>> 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]:

        ```python
        >>> 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[C: SupportsRichComparison](self: Iterum[C]) -> Option[C]:
        """
        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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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[C: SupportsRichComparison](self: Iterum[C]) -> Option[C]:
        """
        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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

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

        ```

        Calling [nth][iterum.Iterum.nth] multiple times doesn't rewind the iterum:

        ```python
        >>> 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:

        ```python
        >>> 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(  # type: ignore
        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:**

        ```python
        >>> 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:

        ```python
        >>> 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[U, V](
        self: Iterum[tuple[U, V]], f: Callable[[T_co], object], container: type[dict], /
    ) -> tuple[dict[U, V], dict[U, V]]: ...

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

    def partition[U](  # 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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

        ```

        ```python
        >>> 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:**

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

        ```

        ```python
        >>> 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[M: SupportsMul](self: Iterum[M]) -> Option[M]:
        """
        Iterates over the entire iterum, multiplying all the elements

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

        **Examples:**

        ```python
        >>> 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:**

        ```python
        >>> 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[U, V](
        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:**

        ```python
        >>> 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:**

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

        ```

        Skipping past end:

        ```python
        >>> 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:**

        ```python
        >>> 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:

        ```python
        >>> 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:**

        ```python
        >>> 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[S: SupportsAdd](self: Iterum[S]) -> Option[S]:
        """
        Sums the elements of an iterum.

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

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

        **Examples:**

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

        ```

        ```python
        >>> 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:**

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

        ```

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

        ```

        Truncate an infinite iterum:

        ```python
        >>> 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:

        ```python
        >>> 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:**

        ```python
        >>> 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`:

        ```python
        >>> 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[U](
        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:**

        ```python
        >>> 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:

        ```python
        >>> 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[U, V](self: Iterum[tuple[U, V]], /) -> tuple[list[U], list[V]]: ...

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

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

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

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

    def unzip[U](
        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:**

        ```python
        >>> 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, strict=False))
        return left, right

    def zip[U](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:**

        ```python
        >>> 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:

        ```python
        >>> 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:

        ```python
        >>> 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)

__slots__ class-attribute instance-attribute

__slots__ = ()

next abstractmethod

next() -> Option[T_co]

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 src/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:**

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

    ```

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

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

    ```

    ... and then [nil][iterum.nil] once it's over.

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

    ```

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

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

    ```
    """
    return nil

__subclasshook__ classmethod

__subclasshook__(C)
Source code in src/iterum/_iterum.py
@classmethod
def __subclasshook__(cls, C):
    if cls is Iterum:
        return check_methods(C, "next")
    return NotImplemented

__next__

__next__() -> T_co
Source code in src/iterum/_iterum.py
@override
def __next__(self) -> T_co:
    return self.next().ok_or_else(StopIteration)

all

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 src/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:**

    ```python
    >>> 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`:

    ```python
    >>> itr = iterum([1, 2, 3])
    >>> assert not itr.all(lambda x: x != 2)
    >>> assert itr.next() == Some(3)

    ```
    """
    return all(map(f, self))

any

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 src/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:**

    ```python
    >>> 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`:

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

    ```

    itr still has more elements.

    ```python
    >>> assert itr.next() == Some(2)

    ```
    """
    return any(map(f, self))

chain

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 src/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:**

    ```python
    >>> 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

cmp(other: Iterable[object]) -> Ordering
cmp(other: Iterable[SupportsRichComparison]) -> Ordering
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 src/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:**

    ```python
    >>> 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

collect() -> list[T_co]
collect(container: type[list]) -> list[T_co]
collect(container: type[set]) -> set[T_co]
collect(container: type[tuple]) -> tuple[T_co, ...]
collect(container: type[dict]) -> dict[U, V]
collect(container: Callable[[Iterable[T_co]], U]) -> U
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 src/iterum/_iterum.py
def collect[U](  # 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:**

    ```python
    >>> 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`

    ```python
    >>> assert iterum("test").map(str.upper).collect("".join) == "TEST"

    ```
    """
    return container(self)

count

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 src/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:**

    ```python
    >>> 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() -> 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 src/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:**

    ```python
    >>> 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() -> 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 src/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:**

    ```python
    >>> 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

eq(other: Iterable[object]) -> bool
eq(other: Iterable[SupportsRichComparison]) -> bool
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 src/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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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

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 src/iterum/_iterum.py
def filter_map[U](
    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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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`:

    ```python
    >>> 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

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 src/iterum/_iterum.py
def find_map[U](self, predicate: Callable[[T_co], Option[U]], /) -> Option[U]:
    """
    Applies function to the elements of iterum and returns the first
    non-nil result.

    **Examples:**

    ```python
    >>> 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

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 src/iterum/_iterum.py
def flat_map[U](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:**

    ```python
    >>> words = ["alpha", "beta", "gamma"]
    >>> merged = iterum(words).flat_map(iterum).collect("".join)
    >>> assert merged == "alphabetagamma"

    ```
    """
    return FlatMap(self, f)

flatten

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 src/iterum/_iterum.py
def flatten[U](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:**

    ```python
    >>> 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:

    ```python
    >>> words = ["alpha", "beta", "gamma"]
    >>> merged = iterum(words).map(iterum).flatten().collect("".join)
    >>> assert merged == "alphabetagamma"

    ```
    """
    return Flatten(self)

fold

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 src/iterum/_iterum.py
def fold[U](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:**

    ```python
    >>> 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.


    ??? note "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

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 src/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:**

    ```python
    >>> 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() -> 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 src/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:**

    ```python
    >>> 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()
    ...

    ```

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

    ```

    ```python
    >>> it = it.fuse()
    >>> assert list(it) == [16, 17, 18, 19]
    >>> assert list(it) == []
    >>> assert list(it) == []

    ```
    """
    return Fuse(self)

ge

ge(other: Iterable[object]) -> bool
ge(other: Iterable[SupportsRichComparison]) -> bool
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 src/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:**

    ```python
    >>> 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

gt(other: Iterable[object]) -> bool
gt(other: Iterable[SupportsRichComparison]) -> bool
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 src/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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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

    ```

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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

le(other: Iterable[object]) -> bool
le(other: Iterable[SupportsRichComparison]) -> bool
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 src/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:**

    ```python
    >>> 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

lt(other: Iterable[object]) -> bool
lt(other: Iterable[SupportsRichComparison]) -> bool
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 src/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:**

    ```python
    >>> 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

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 src/iterum/_iterum.py
def map[U](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:**

    ```python
    >>> 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

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 src/iterum/_iterum.py
def map_while[U](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:**

    ```python
    >>> 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]:

    ```python
    >>> 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

max() -> Option[C]

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 src/iterum/_iterum.py
def max[C: SupportsRichComparison](self: Iterum[C]) -> Option[C]:
    """
    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:**

    ```python
    >>> assert iterum([1, 2, 3]).max() == Some(3)
    >>> assert iterum([]).max() == nil

    ```
    """
    try:
        return Some(builtins.max(self))
    except ValueError:
        return nil

max_by

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 src/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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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

min() -> Option[C]

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 src/iterum/_iterum.py
def min[C: SupportsRichComparison](self: Iterum[C]) -> Option[C]:
    """
    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:**

    ```python
    >>> assert iterum([1, 2, 3]).min() == Some(1)
    >>> assert iterum([]).min() == nil

    ```
    """
    try:
        return Some(builtins.min(self))
    except ValueError:
        return nil

min_by

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 src/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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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

ne(other: Iterable[object]) -> bool
ne(other: Iterable[SupportsRichComparison]) -> bool
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 src/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:**

    ```python
    >>> 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

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 src/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:**

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

    ```

    Calling [nth][iterum.Iterum.nth] multiple times doesn't rewind the iterum:

    ```python
    >>> 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:

    ```python
    >>> 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

partial_cmp(other: Iterable[object]) -> Some[Ordering]
partial_cmp(
    other: Iterable[SupportsRichComparison],
) -> Some[Ordering]
partial_cmp(other: Iterable[object]) -> 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 src/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:**

    ```python
    >>> 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:

    ```python
    >>> 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

partition(
    f: Callable[[T_co], object],
) -> tuple[list[T_co], list[T_co]]
partition(
    f: Callable[[T_co], object], container: type[list]
) -> tuple[list[T_co], list[T_co]]
partition(
    f: Callable[[T_co], object], container: type[set]
) -> tuple[set[T_co], set[T_co]]
partition(
    f: Callable[[T_co], object], container: type[tuple]
) -> tuple[tuple[T_co, ...], tuple[T_co, ...]]
partition(
    f: Callable[[T_co], object], container: type[dict]
) -> tuple[dict[U, V], dict[U, V]]
partition(
    f: Callable[[T_co], object],
    container: Callable[[Iterable[T_co]], U],
) -> tuple[U, U]
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 src/iterum/_iterum.py
def partition[U](  # 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:**

    ```python
    >>> 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() -> 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 src/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:**

    ```python
    >>> 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

    ```

    ```python
    >>> 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

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 src/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:**

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

    ```

    ```python
    >>> 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

product() -> Option[M]

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 src/iterum/_iterum.py
def product[M: SupportsMul](self: Iterum[M]) -> Option[M]:
    """
    Iterates over the entire iterum, multiplying all the elements

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

    **Examples:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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

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 src/iterum/_iterum.py
def scan[U, V](
    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:**

    ```python
    >>> 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

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 src/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:**

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

    ```

    Skipping past end:

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

    ```
    """
    return Skip(self, n)

skip_while

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 src/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:**

    ```python
    >>> 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:

    ```python
    >>> 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_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 src/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:**

    ```python
    >>> 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

sum() -> Option[S]

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 src/iterum/_iterum.py
def sum[S: SupportsAdd](self: Iterum[S]) -> Option[S]:
    """
    Sums the elements of an iterum.

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

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

    **Examples:**

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

    ```

    ```python
    >>> 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

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 src/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:**

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

    ```

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

    ```

    Truncate an infinite iterum:

    ```python
    >>> 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:

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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`:

    ```python
    >>> 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

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 src/iterum/_iterum.py
def try_fold[U](
    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:**

    ```python
    >>> 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:

    ```python
    >>> 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

unzip() -> tuple[list[U], list[V]]
unzip(container: type[list]) -> tuple[list[U], list[V]]
unzip(container: type[set]) -> tuple[set[U], set[V]]
unzip(
    container: type[tuple],
) -> tuple[tuple[U, ...], tuple[V, ...]]
unzip(
    container: Callable[[Iterable[object]], U],
) -> tuple[U, U]
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 src/iterum/_iterum.py
def unzip[U](
    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:**

    ```python
    >>> 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, strict=False))
    return left, right

zip

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 src/iterum/_iterum.py
def zip[U](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:**

    ```python
    >>> 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:

    ```python
    >>> 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:

    ```python
    >>> 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 src/iterum/_diterum.py
class diterum(Diterum[T_co]):
    """
    Implements a [Diterum][iterum.Diterum] interface from a sequence.

    **Examples:**

    ```python
    >>> 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

    ```

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

    ```

    ```python
    >>> 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__ = ("_back", "_front", "_seq")

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

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

        **Examples:**

        ```python
        >>> 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)

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

        **Examples:**

        ```python
        >>> 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)

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

        **Examples:**

        ```python
        >>> 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

__slots__ class-attribute instance-attribute

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

__init__

__init__(__seq: Sequence[T_co]) -> None
Source code in src/iterum/_diterum.py
def __init__(self, __seq: Sequence[T_co], /) -> None:
    self._seq = __seq
    self._front = 0
    self._back = len(__seq) - 1

next

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 src/iterum/_diterum.py
@override
def next(self) -> Option[T_co]:
    """
    Returns the next value in the sequence from the front if present,
    otherwise [nil][iterum.nil].

    **Examples:**

    ```python
    >>> 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

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 src/iterum/_diterum.py
@override
def next_back(self) -> Option[T_co]:
    """
    Returns the next value in the sequence from the back if present,
    otherwise [nil][iterum.nil].

    **Examples:**

    ```python
    >>> 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

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 src/iterum/_diterum.py
@override
def len(self) -> int:
    """
    Returns the remaining length of the sequence.

    **Examples:**

    ```python
    >>> 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 src/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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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`:

        ```python
        >>> 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:**

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

        ```

        Does not rewind:

        ```python
        >>> 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:

        ```python
        >>> 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:**

        ```python
        >>> 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`:

        ```python
        >>> 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[U](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:**

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

        ```

        ??? note "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[U](
        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:**

        ```python
        >>> 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)

__slots__ class-attribute instance-attribute

__slots__ = ()

next_back abstractmethod

next_back() -> Option[T_co]

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 src/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:**

    ```python
    >>> 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 abstractmethod

len() -> 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
Source code in src/iterum/_diterum.py
@abstractmethod
def len(self) -> int:
    """
    Required method.

    Returns the exact remaining length of the diterum.

    **Examples:**

    ```python
    >>> 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() -> 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 src/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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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`:

    ```python
    >>> 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

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 src/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:**

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

    ```

    Does not rewind:

    ```python
    >>> 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:

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

    ```
    """
    return self.rev().nth(n)

rfind

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 src/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:**

    ```python
    >>> 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`:

    ```python
    >>> 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

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 src/iterum/_diterum.py
def rfold[U](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:**

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

    ```

    ??? note "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

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 src/iterum/_diterum.py
def try_rfold[U](
    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:**

    ```python
    >>> 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

seq(
    start: SupportsIndex,
    end: SupportsIndex,
    /,
    step: SupportsIndex = 1,
) -> Seq
seq(
    start: SupportsIndex,
    end: EllipsisType,
    /,
    step: SupportsIndex = 1,
) -> InfSeq
seq(
    end: SupportsIndex, /, *, step: SupportsIndex = 1
) -> Seq
seq(
    end: EllipsisType, /, *, step: SupportsIndex = 1
) -> InfSeq
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 src/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:**

    ```python
    >>> 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:

    ```python
    >>> 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]:

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


    ```

    Specify an infinite range using `...`:

    ```python
    >>> 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:

    ```python
    >>> 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

Option = Some[T] | Nil

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

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 src/iterum/_option.py
 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
class Some[T]:
    """
    [Some][iterum.Some] value of type T.

    **Examples:**

    ```python
    >>> 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_[O: Option](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:**

        ```python
        >>> 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[O: Option](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:**

        ```python
        >>> 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:**

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

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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[O: Option](self: Some[O]) -> O:
        """Converts from `Option[Option[T]]` to `Option[T]`.

        **Examples:**

        ```python
        >>> 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:**

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

        ```

        ```python
        >>> 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]:

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

        ```

        ```python
        >>> 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:**

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

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(10).get_or_insert_with(lambda: 5)
        >>> assert swap.inserted == Some(10)
        >>> assert swap.returned == 10

        ```

        ```python
        >>> 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:**

        ```python
        >>> opt = nil
        >>> opt, value = opt.insert(1)
        >>> assert value == 1
        >>> assert opt == Some(1)

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(10).insert(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> assert Some(4).iter().next() == Some(4)
        >>> assert nil.iter().next() == nil

        ```
        """
        from ._iterum import iterum

        return iterum([self._value])

    def map[U](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:**

        ```python
        >>> assert Some("Hello, World!").map(len) == Some(13)
        >>> assert nil.map(len) == nil

        ```
        """
        return Some(f(self._value))

    def map_or[U](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:**

        ```python
        >>> assert Some("foo").map_or(42, len) == 3
        >>> assert nil.map_or(42, len) == 42

        ```
        """
        return f(self._value)

    def map_or_else[U](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:**

        ```python
        >>> 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:**

        ```python
        >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

        ```

        ```python
        >>> 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:**

        ```python
        >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> x = Some(2)
        >>> new, old = x.replace(5)
        >>> assert new == Some(5)
        >>> assert old == Some(2)

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(10).replace(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == Some(10)

        ```

        ```python
        >>> 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:**

        ```python
        >>> x = Some(2)
        >>> new, old = x.take()
        >>> assert new == nil
        >>> assert old == Some(2)

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(2).take()
        >>> assert swap.inserted == nil
        >>> assert swap.returned == Some(2)

        ```

        ```python
        >>> 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:**

        ```python
        >>> assert Some("air").unwrap() == "air"

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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[U, V](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:**

        ```python
        >>> 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:**

        ```python
        >>> 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[U](self, other: Some[U], /) -> Some[tuple[T, U]]: ...

    @overload
    def zip(self, other: Nil, /) -> Nil: ...

    def zip[U](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:**

        ```python
        >>> 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))

__match_args__ class-attribute instance-attribute

__match_args__ = ('_value',)

__init__

__init__(value: T) -> None
Source code in src/iterum/_option.py
def __init__(self, value: T, /) -> None:
    self._value = value

__eq__

__eq__(other: object) -> bool
Source code in src/iterum/_option.py
def __eq__(self, other: object) -> bool:
    if not isinstance(other, Some):
        return NotImplemented
    return self._value == other._value

__repr__

__repr__() -> str
Source code in src/iterum/_option.py
def __repr__(self) -> str:
    return f"{Some.__name__}({self._value!r})"

__bool__

__bool__() -> Literal[True]
Source code in src/iterum/_option.py
def __bool__(self) -> Literal[True]:
    return True

and_

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 src/iterum/_option.py
def and_[O: Option](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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def and_then[O: Option](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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def expect(self, msg: str, /) -> T:
    """Returns the contained [Some][iterum.Some] value, consuming the self value.

    **Examples:**

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

    ```

    ```python
    >>> 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

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) if the predicate returns True
  • 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 src/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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def flatten[O: Option](self: Some[O]) -> O:
    """Converts from `Option[Option[T]]` to `Option[T]`.

    **Examples:**

    ```python
    >>> 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

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 src/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:**

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

    ```

    ```python
    >>> 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]:

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

    ```

    ```python
    >>> 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

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 src/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:**

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

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(10).get_or_insert_with(lambda: 5)
    >>> assert swap.inserted == Some(10)
    >>> assert swap.returned == 10

    ```

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> opt = nil
    >>> opt, value = opt.insert(1)
    >>> assert value == 1
    >>> assert opt == Some(1)

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(10).insert(5)
    >>> assert swap.inserted == Some(5)
    >>> assert swap.returned == 5

    ```

    ```python
    >>> 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

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 src/iterum/_option.py
def is_nil(self) -> Literal[False]:
    """Returns `True` if the option is a [nil][iterum.nil] value.

    **Examples:**

    ```python
    >>> assert Some(2).is_nil() is False
    >>> assert nil.is_nil() is True

    ```
    """
    return False

is_some

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 src/iterum/_option.py
def is_some(self) -> Literal[True]:
    """Returns `True` if the option is a Some value.

    **Examples:**

    ```python
    >>> assert Some(2).is_some() is True
    >>> assert nil.is_some() is False

    ```
    """
    return True

is_some_and

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 src/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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def iter(self) -> iterum[T]:
    """Returns an iterator over the possibly contained value.

    **Examples:**

    ```python
    >>> assert Some(4).iter().next() == Some(4)
    >>> assert nil.iter().next() == nil

    ```
    """
    from ._iterum import iterum

    return iterum([self._value])

map

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 src/iterum/_option.py
def map[U](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:**

    ```python
    >>> assert Some("Hello, World!").map(len) == Some(13)
    >>> assert nil.map(len) == nil

    ```
    """
    return Some(f(self._value))

map_or

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 src/iterum/_option.py
def map_or[U](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:**

    ```python
    >>> assert Some("foo").map_or(42, len) == 3
    >>> assert nil.map_or(42, len) == 42

    ```
    """
    return f(self._value)

map_or_else

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 src/iterum/_option.py
def map_or_else[U](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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

    ```

    ```python
    >>> try:
    ...     nil.ok_or(RuntimeError("oh no!"))
    ... except RuntimeError as ex:
    ...     print(ex)
    ...
    oh no!

    ```
    """
    return self._value

ok_or_else

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 src/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:**

    ```python
    >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

    ```

    ```python
    >>> try:
    ...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
    ... except AssertionError as ex:
    ...     print(ex)
    ...
    oopsy!

    ```
    """
    return self._value

or_

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 src/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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> x = Some(2)
    >>> new, old = x.replace(5)
    >>> assert new == Some(5)
    >>> assert old == Some(2)

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(10).replace(5)
    >>> assert swap.inserted == Some(5)
    >>> assert swap.returned == Some(10)

    ```

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> x = Some(2)
    >>> new, old = x.take()
    >>> assert new == nil
    >>> assert old == Some(2)

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(2).take()
    >>> assert swap.inserted == nil
    >>> assert swap.returned == Some(2)

    ```

    ```python
    >>> swap = nil.take()
    >>> assert swap.inserted == nil
    >>> assert swap.returned == nil

    ```
    """
    return Swap(nil, self)

unwrap

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 src/iterum/_option.py
def unwrap(self) -> T:
    """Returns the contained [Some][iterum.Some] value.

    **Examples:**

    ```python
    >>> assert Some("air").unwrap() == "air"

    ```

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> assert Some("car").unwrap_or("bike") == "car"
    >>> assert nil.unwrap_or("bike") == "bike"

    ```
    """
    return self._value

unwrap_or_else

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 src/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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def unzip[U, V](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:**

    ```python
    >>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
    >>> assert nil.unzip() == (nil, nil)

    ```
    """
    left, right = self._value
    return Some(left), Some(right)

xor

xor(optb: Some[T]) -> Nil
xor(optb: Nil) -> Some[T]
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 src/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:**

    ```python
    >>> 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

zip(other: Some[U]) -> Some[tuple[T, U]]
zip(other: Nil) -> 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 src/iterum/_option.py
def zip[U](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:**

    ```python
    >>> 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 src/iterum/_option.py
 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
class Nil(Singleton):
    """
    [Nil][iterum.Nil] has no value.

    **Examples:**

    ```python
    >>> 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.

    ```python
    >>> 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_[U](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:**

        ```python
        >>> 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[U](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:**

        ```python
        >>> 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:**

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

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> assert Some(Some(6)).flatten() == Some(6)
        >>> assert Some(nil).flatten() == nil
        >>> assert nil.flatten() == nil

        ```
        """
        return self

    def get_or_insert[T](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:**

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

        ```

        ```python
        >>> 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]:

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

        ```

        ```python
        >>> 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[T](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:**

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

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(10).get_or_insert_with(lambda: 5)
        >>> assert swap.inserted == Some(10)
        >>> assert swap.returned == 10

        ```

        ```python
        >>> 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[T](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:**

        ```python
        >>> opt = nil
        >>> opt, value = opt.insert(1)
        >>> assert value == 1
        >>> assert opt == Some(1)

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(10).insert(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == 5

        ```

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> 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:**

        ```python
        >>> assert Some("Hello, World!").map(len) == Some(13)
        >>> assert nil.map(len) == nil

        ```
        """
        return self

    def map_or[U](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:**

        ```python
        >>> assert Some("foo").map_or(42, len) == 3
        >>> assert nil.map_or(42, len) == 42

        ```
        """
        return default

    def map_or_else[U](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:**

        ```python
        >>> 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:**

        ```python
        >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

        ```

        ```python
        >>> 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:**

        ```python
        >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

        ```

        ```python
        >>> try:
        ...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
        ... except AssertionError as ex:
        ...     print(ex)
        ...
        oopsy!

        ```
        """
        raise err()

    def or_[O: Option](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:**

        ```python
        >>> 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[O: Option](self, f: Callable[[], O], /) -> O:
        """
        Returns the option if it contains a value, otherwise calls `f` and
        returns the result.

        **Examples:**

        ```python
        >>> 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[T](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:**

        ```python
        >>> x = Some(2)
        >>> new, old = x.replace(5)
        >>> assert new == Some(5)
        >>> assert old == Some(2)

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(10).replace(5)
        >>> assert swap.inserted == Some(5)
        >>> assert swap.returned == Some(10)

        ```

        ```python
        >>> 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:**

        ```python
        >>> x = Some(2)
        >>> new, old = x.take()
        >>> assert new == nil
        >>> assert old == Some(2)

        ```

        ```python
        >>> 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]:

        ```python
        >>> swap = Some(2).take()
        >>> assert swap.inserted == nil
        >>> assert swap.returned == Some(2)

        ```

        ```python
        >>> 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:**

        ```python
        >>> assert Some("air").unwrap() == "air"

        ```

        ```python
        >>> 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[T](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:**

        ```python
        >>> 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[T](self, f: Callable[[], T], /) -> T:
        """
        Returns the contained [Some][iterum.Some] value or computes it from a closure.

        **Examples:**

        ```python
        >>> 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:**

        ```python
        >>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
        >>> assert nil.unzip() == (nil, nil)

        ```
        """
        return (nil, nil)

    @overload
    def xor[S: Some](self, optb: S, /) -> S: ...

    @overload
    def xor(self, optb: Nil, /) -> Nil: ...

    def xor[O: Option](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:**

        ```python
        >>> 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[U](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:**

        ```python
        >>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
        >>> assert Some(1).zip(nil) == nil
        >>> assert nil.zip(nil) == nil

        ```
        """
        return self

__slots__ class-attribute instance-attribute

__slots__ = ()

__repr__

__repr__() -> str
Source code in src/iterum/_option.py
def __repr__(self) -> str:
    return "nil"

__bool__

__bool__() -> Literal[False]
Source code in src/iterum/_option.py
def __bool__(self) -> Literal[False]:
    return False

and_

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 src/iterum/_option.py
def and_[U](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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def and_then[U](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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def expect(self, msg: str, /) -> NoReturn:
    """
    Returns the contained [Some][iterum.Some] value, consuming the self value.

    **Examples:**

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

    ```

    ```python
    >>> 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

filter(predicate: Callable[[Any], object]) -> Nil

Returns nil if the option is nil, otherwise calls predicate with the wrapped value and returns:

  • Some(value) if the predicate returns True
  • 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 src/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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def flatten(self) -> Nil:
    """
    Converts from `Option[Option[T]]` to `Option[T]`.

    **Examples:**

    ```python
    >>> assert Some(Some(6)).flatten() == Some(6)
    >>> assert Some(nil).flatten() == nil
    >>> assert nil.flatten() == nil

    ```
    """
    return self

get_or_insert

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 src/iterum/_option.py
def get_or_insert[T](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:**

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

    ```

    ```python
    >>> 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]:

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

    ```

    ```python
    >>> 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

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 src/iterum/_option.py
def get_or_insert_with[T](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:**

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

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(10).get_or_insert_with(lambda: 5)
    >>> assert swap.inserted == Some(10)
    >>> assert swap.returned == 10

    ```

    ```python
    >>> swap = nil.get_or_insert_with(lambda: 5)
    >>> assert swap.inserted == Some(5)
    >>> assert swap.returned == 5

    ```
    """
    return Swap(Some(value := f()), value)

insert

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 src/iterum/_option.py
def insert[T](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:**

    ```python
    >>> opt = nil
    >>> opt, value = opt.insert(1)
    >>> assert value == 1
    >>> assert opt == Some(1)

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(10).insert(5)
    >>> assert swap.inserted == Some(5)
    >>> assert swap.returned == 5

    ```

    ```python
    >>> swap = nil.insert(5)
    >>> assert swap.inserted == Some(5)
    >>> assert swap.returned == 5

    ```
    """
    return Swap(Some(value), value)

is_nil

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 src/iterum/_option.py
def is_nil(self) -> Literal[True]:
    """
    Returns `True` if the option is a [nil][iterum.nil] value.

    **Examples:**

    ```python
    >>> assert Some(2).is_nil() is False
    >>> assert nil.is_nil() is True

    ```
    """
    return True

is_some

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 src/iterum/_option.py
def is_some(self) -> Literal[False]:
    """
    Returns `True` if the option is a Some value.

    **Examples:**

    ```python
    >>> assert Some(2).is_some() is True
    >>> assert nil.is_some() is False

    ```
    """
    return False

is_some_and

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 src/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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def iter(self) -> iterum[Any]:
    """
    Returns an iterator over the possibly contained value.

    **Examples:**

    ```python
    >>> assert Some(4).iter().next() == Some(4)
    >>> assert nil.iter().next() == nil

    ```
    """
    from ._iterum import iterum

    return iterum([])

map

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 src/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:**

    ```python
    >>> assert Some("Hello, World!").map(len) == Some(13)
    >>> assert nil.map(len) == nil

    ```
    """
    return self

map_or

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 src/iterum/_option.py
def map_or[U](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:**

    ```python
    >>> assert Some("foo").map_or(42, len) == 3
    >>> assert nil.map_or(42, len) == 42

    ```
    """
    return default

map_or_else

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 src/iterum/_option.py
def map_or_else[U](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:**

    ```python
    >>> 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

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 src/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:**

    ```python
    >>> assert Some("foo").ok_or(RuntimeError("oh no!")) == "foo"

    ```

    ```python
    >>> try:
    ...     nil.ok_or(RuntimeError("oh no!"))
    ... except RuntimeError as ex:
    ...     print(ex)
    ...
    oh no!

    ```
    """
    raise err

ok_or_else

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 src/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:**

    ```python
    >>> assert Some("foo").ok_or_else(AssertionError) == "foo"

    ```

    ```python
    >>> try:
    ...     nil.ok_or_else(lambda: AssertionError("oopsy!"))
    ... except AssertionError as ex:
    ...     print(ex)
    ...
    oopsy!

    ```
    """
    raise err()

or_

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 src/iterum/_option.py
def or_[O: Option](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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def or_else[O: Option](self, f: Callable[[], O], /) -> O:
    """
    Returns the option if it contains a value, otherwise calls `f` and
    returns the result.

    **Examples:**

    ```python
    >>> 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

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 src/iterum/_option.py
def replace[T](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:**

    ```python
    >>> x = Some(2)
    >>> new, old = x.replace(5)
    >>> assert new == Some(5)
    >>> assert old == Some(2)

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(10).replace(5)
    >>> assert swap.inserted == Some(5)
    >>> assert swap.returned == Some(10)

    ```

    ```python
    >>> swap = nil.replace(5)
    >>> assert swap.inserted == Some(5)
    >>> assert swap.returned == nil

    ```
    """
    return Swap(Some(value), nil)

take

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 src/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:**

    ```python
    >>> x = Some(2)
    >>> new, old = x.take()
    >>> assert new == nil
    >>> assert old == Some(2)

    ```

    ```python
    >>> 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]:

    ```python
    >>> swap = Some(2).take()
    >>> assert swap.inserted == nil
    >>> assert swap.returned == Some(2)

    ```

    ```python
    >>> swap = nil.take()
    >>> assert swap.inserted == nil
    >>> assert swap.returned == nil

    ```
    """
    return Swap(nil, self)

unwrap

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 src/iterum/_option.py
def unwrap(self) -> NoReturn:
    """
    Returns the contained [Some][iterum.Some] value.

    **Examples:**

    ```python
    >>> assert Some("air").unwrap() == "air"

    ```

    ```python
    >>> 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

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 src/iterum/_option.py
def unwrap_or[T](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:**

    ```python
    >>> assert Some("car").unwrap_or("bike") == "car"
    >>> assert nil.unwrap_or("bike") == "bike"

    ```
    """
    return default

unwrap_or_else

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 src/iterum/_option.py
def unwrap_or_else[T](self, f: Callable[[], T], /) -> T:
    """
    Returns the contained [Some][iterum.Some] value or computes it from a closure.

    **Examples:**

    ```python
    >>> k = 10
    >>> assert Some(4).unwrap_or_else(lambda: 2 * k) == 4
    >>> assert nil.unwrap_or_else(lambda: 2 * k) == 20

    ```
    """
    return f()

unzip

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 src/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:**

    ```python
    >>> assert Some((1, "hi")).unzip() == (Some(1), Some("hi"))
    >>> assert nil.unzip() == (nil, nil)

    ```
    """
    return (nil, nil)

xor

xor(optb: S) -> S
xor(optb: 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 src/iterum/_option.py
def xor[O: Option](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:**

    ```python
    >>> 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

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 src/iterum/_option.py
def zip[U](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:**

    ```python
    >>> assert Some(1).zip(Some("hi")) == Some((1, "hi"))
    >>> assert Some(1).zip(nil) == nil
    >>> assert nil.zip(nil) == nil

    ```
    """
    return self

iterum.nil module-attribute

nil = Nil()

Instance of type Nil. See Nil for more details.

iterum.is_some

is_some(o: Option[T]) -> TypeIs[Some[T]]

Returns True if the option is a Some value.

Examples:

>>> assert is_some(Some(2)) is True
>>> assert is_some(nil) is False
This method is provided as a standalone function in order

to leverage TypeIs, which provides better typing.

Source code in src/iterum/_option.py
def is_some[T](o: Option[T], /) -> TypeIs[Some[T]]:
    """Returns `True` if the option is a Some value.

    **Examples:**

    ```python
    >>> assert is_some(Some(2)) is True
    >>> assert is_some(nil) is False

    ```

    Note: This method is provided as a standalone function in order
          to leverage `TypeIs`, which provides better typing.
    """
    return o is not nil

iterum.is_nil

is_nil(o: Option[T]) -> TypeIs[Nil]

Returns True if the option is a nil value.

Examples:

>>> assert is_nil(Some(2)) is False
>>> assert is_nil(nil) is True
This method is provided as a standalone function in order

to leverage TypeIs, which provides better typing.

Source code in src/iterum/_option.py
def is_nil[T](o: Option[T], /) -> TypeIs[Nil]:
    """Returns `True` if the option is a [nil][iterum.nil] value.

    **Examples:**

    ```python
    >>> assert is_nil(Some(2)) is False
    >>> assert is_nil(nil) is True

    ```

    Note: This method is provided as a standalone function in order
          to leverage `TypeIs`, which provides better typing.
    """
    return o is nil

iterum.ExpectNilError

Bases: RuntimeError

Exception raised when nil.expect is called.

Source code in src/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)

__init__

__init__(
    msg: str = "Expected some but option is nil",
) -> None
Source code in src/iterum/_option.py
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 src/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)

__init__

__init__(msg: str = 'Attempted to unwrap nil') -> None
Source code in src/iterum/_option.py
def __init__(self, msg: str = "Attempted to unwrap nil") -> None:
    super().__init__(msg)


Other


iterum.State dataclass

Simple class which holds some mutable state.

Source code in src/iterum/_iterum.py
@dataclass
class State[T]:
    """
    Simple class which holds some mutable state.
    """

    value: T
    """
    current value of the state
    """

value instance-attribute

value: T

current value of the state

__init__

__init__(value: T) -> None

iterum.Swap

Bases: NamedTuple

Used for various 'swapping' operations on Option.

Source code in src/iterum/_option.py
class Swap[T, U](NamedTuple):
    """
    Used for various 'swapping' operations on [Option][iterum.Option].
    """

    inserted: T
    """
    Value inserted into an option
    """

    returned: U
    """
    Value returned from an option
    """

inserted instance-attribute

inserted: T

Value inserted into an option

returned instance-attribute

returned: U

Value returned from an option

iterum.Ordering

Bases: Enum

An Ordering is the result of a comparison between two values.

Source code in src/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:

        ```python
        >>> 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:

        ```python
        >>> 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 class-attribute instance-attribute

Less = create_singleton('Less')

An ordering where a compared value is less than another.

Equal class-attribute instance-attribute

Equal = create_singleton('Equal')

An ordering where a compared value is equal to another.

Greater class-attribute instance-attribute

Greater = create_singleton('Greater')

An ordering where a compared value is greater than another.

cmp staticmethod

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'
Source code in src/iterum/_ordering.py
@staticmethod
def cmp(lhs, rhs, /) -> Ordering:
    """
    Compare two values.

    Examples:

    ```python
    >>> 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:

    ```python
    >>> 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}")

__repr__

__repr__() -> str
Source code in src/iterum/_ordering.py
def __repr__(self) -> str:
    return f"{type(self).__name__}.{self.name}"

iterum.Chain

Bases: _IterumAdapter[T_co]

Source code in src/iterum/_iterum.py
class Chain(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

    def __init__(self, *__iterables: Iterable[T_co]) -> None:
        self._iter = itertools.chain(*__iterables)

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(*__iterables: Iterable[T_co]) -> None
Source code in src/iterum/_iterum.py
def __init__(self, *__iterables: Iterable[T_co]) -> None:
    self._iter = itertools.chain(*__iterables)

iterum.Cycle

Bases: _IterumAdapter[T_co]

Source code in src/iterum/_iterum.py
class Cycle(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

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

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(__iterable: Iterable[T_co]) -> None
Source code in src/iterum/_iterum.py
def __init__(self, __iterable: Iterable[T_co]) -> None:
    self._iter = itertools.cycle(__iterable)

iterum.Enumerate

Bases: _IterumAdapter[tuple[int, T_co]]

Source code in src/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)

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(__iterable: Iterable[T_co]) -> None
Source code in src/iterum/_iterum.py
def __init__(self, __iterable: Iterable[T_co], /) -> None:
    self._iter = builtins.enumerate(__iterable)

iterum.Filter

Bases: _IterumAdapter[T_co]

Source code in src/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)

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(
    __iterable: Iterable[T_co],
    predicate: Callable[[T_co], object],
) -> None
Source code in src/iterum/_iterum.py
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 src/iterum/_iterum.py
class FlatMap(_IterumAdapter[T_co]):
    __slots__ = ("_iter",)

    def __init__[U](
        self, __iterable: Iterable[U], f: Callable[[U], Iterable[T_co]], /
    ) -> None:
        self._iter = iterum(__iterable).map(f).flatten()

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(
    __iterable: Iterable[U],
    f: Callable[[U], Iterable[T_co]],
) -> None
Source code in src/iterum/_iterum.py
def __init__[U](
    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 src/iterum/_iterum.py
class FilterMap(Iterum[T_co]):
    __slots__ = ("_iter", "_predicate")

    def __init__[U](
        self, __iterable: Iterable[U], predicate: Callable[[U], Option[T_co]], /
    ) -> None:
        self._iter = iterum(__iterable)
        self._predicate = predicate

    @override
    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

__slots__ class-attribute instance-attribute

__slots__ = ('_iter', '_predicate')

__init__

__init__(
    __iterable: Iterable[U],
    predicate: Callable[[U], Option[T_co]],
) -> None
Source code in src/iterum/_iterum.py
def __init__[U](
    self, __iterable: Iterable[U], predicate: Callable[[U], Option[T_co]], /
) -> None:
    self._iter = iterum(__iterable)
    self._predicate = predicate

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/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)

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(__iterable: Iterable[Iterable[T_co]]) -> None
Source code in src/iterum/_iterum.py
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 src/iterum/_iterum.py
class Fuse(Iterum[T_co]):
    __slots__ = ("_fuse", "_iter")

    def __init__(self, __iterable: Iterable[T_co]) -> None:
        self._iter = iterum(__iterable)
        self._fuse = True

    @override
    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

__slots__ class-attribute instance-attribute

__slots__ = ('_fuse', '_iter')

__init__

__init__(__iterable: Iterable[T_co]) -> None
Source code in src/iterum/_iterum.py
def __init__(self, __iterable: Iterable[T_co]) -> None:
    self._iter = iterum(__iterable)
    self._fuse = True

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/iterum/_iterum.py
class Inspect(Iterum[T_co]):
    __slots__ = ("_f", "_iter")

    def __init__(
        self, __iterable: Iterable[T_co], f: Callable[[T_co], object], /
    ) -> None:
        self._iter = iterum(__iterable)
        self._f = f

    @override
    def next(self) -> Option[T_co]:
        nxt = self._iter.next()
        nxt.map(self._f)
        return nxt

__slots__ class-attribute instance-attribute

__slots__ = ('_f', '_iter')

__init__

__init__(
    __iterable: Iterable[T_co], f: Callable[[T_co], object]
) -> None
Source code in src/iterum/_iterum.py
def __init__(
    self, __iterable: Iterable[T_co], f: Callable[[T_co], object], /
) -> None:
    self._iter = iterum(__iterable)
    self._f = f

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/iterum/_iterum.py
class Map(Iterum[T_co]):
    __slots__ = ("_f", "_iter")

    def __init__[U](self, __iterable: Iterable[U], f: Callable[[U], T_co], /) -> None:
        self._iter = iterum(__iterable)
        self._f = f

    @override
    def next(self) -> Option[T_co]:
        return self._iter.next().map(self._f)

__slots__ class-attribute instance-attribute

__slots__ = ('_f', '_iter')

__init__

__init__(
    __iterable: Iterable[U], f: Callable[[U], T_co]
) -> None
Source code in src/iterum/_iterum.py
def __init__[U](self, __iterable: Iterable[U], f: Callable[[U], T_co], /) -> None:
    self._iter = iterum(__iterable)
    self._f = f

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
def next(self) -> Option[T_co]:
    return self._iter.next().map(self._f)

iterum.MapWhile

Bases: Iterum[T_co]

Source code in src/iterum/_iterum.py
class MapWhile(Iterum[T_co]):
    __slots__ = ("_fuse", "_iter", "_predicate")

    def __init__[U](
        self, __iterable: Iterable[U], predicate: Callable[[U], Option[T_co]], /
    ) -> None:
        self._iter = iterum(__iterable)
        self._predicate = predicate
        self._fuse = True

    @override
    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

__slots__ class-attribute instance-attribute

__slots__ = ('_fuse', '_iter', '_predicate')

__init__

__init__(
    __iterable: Iterable[U],
    predicate: Callable[[U], Option[T_co]],
) -> None
Source code in src/iterum/_iterum.py
def __init__[U](
    self, __iterable: Iterable[U], predicate: Callable[[U], Option[T_co]], /
) -> None:
    self._iter = iterum(__iterable)
    self._predicate = predicate
    self._fuse = True

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/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

    @override
    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)

__slots__ class-attribute instance-attribute

__slots__ = ('_iter', '_peek')

peek property writable

peek: Option[T_co]

__init__

__init__(__iterable: Iterable[T_co]) -> None
Source code in src/iterum/_iterum.py
def __init__(self, __iterable: Iterable[T_co], /) -> None:
    self._iter = iterum(__iterable)
    self._peek: Option[T_co] | NotSetType = NotSet

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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

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 src/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)

    @override
    def next(self) -> Option[T_co]:
        return self._x.next_back()

    @override
    def next_back(self) -> Option[T_co]:
        return self._x.next()

    @override
    def len(self) -> int:
        return self._x.len()

__slots__ class-attribute instance-attribute

__slots__ = ('_x',)

__init__

__init__(__x: Diterum[T_co] | Sequence[T_co]) -> None
Source code in src/iterum/_diterum.py
def __init__(self, __x: Diterum[T_co] | Sequence[T_co]) -> None:
    self._x = __x if isinstance(__x, Diterum) else diterum(__x)

next

next() -> Option[T_co]
Source code in src/iterum/_diterum.py
@override
def next(self) -> Option[T_co]:
    return self._x.next_back()

next_back

next_back() -> Option[T_co]
Source code in src/iterum/_diterum.py
@override
def next_back(self) -> Option[T_co]:
    return self._x.next()

len

len() -> int
Source code in src/iterum/_diterum.py
@override
def len(self) -> int:
    return self._x.len()

iterum.Scan

Bases: Iterum[T_co]

Source code in src/iterum/_iterum.py
class Scan(Iterum[T_co]):
    __slots__ = ("_f", "_iter", "_state")

    def __init__[U, V](
        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

    @override
    def next(self) -> Option[T_co]:
        def scan(val) -> Option[T_co]:
            return self._f(self._state, val)

        return self._iter.next().map(scan).flatten()

__slots__ class-attribute instance-attribute

__slots__ = ('_f', '_iter', '_state')

__init__

__init__(
    __iterable: Iterable[U],
    init: V,
    f: Callable[[State[V], U], Option[T_co]],
)
Source code in src/iterum/_iterum.py
def __init__[U, V](
    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

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
def next(self) -> Option[T_co]:
    def scan(val) -> Option[T_co]:
        return self._f(self._state, val)

    return self._iter.next().map(scan).flatten()

iterum.Skip

Bases: Iterum[T_co]

Source code in src/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

    @override
    def next(self) -> Option[T_co]:
        if self._n:
            self._iter.nth(self._n - 1)
            self._n = 0

        return self._iter.next()

__slots__ class-attribute instance-attribute

__slots__ = ('_iter', '_n')

__init__

__init__(__iterable: Iterable[T_co], n: int) -> None
Source code in src/iterum/_iterum.py
def __init__(
    self,
    __iterable: Iterable[T_co],
    n: int,
    /,
) -> None:
    self._iter = iterum(__iterable)
    self._n = n

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/iterum/_iterum.py
class SkipWhile(Iterum[T_co]):
    __slots__ = ("_fuse", "_iter", "_predicate")

    def __init__(
        self,
        __iterable: Iterable[T_co],
        predicate: Callable[[T_co], object],
        /,
    ) -> None:
        self._iter = iterum(__iterable)
        self._predicate = predicate
        self._fuse = True

    @override
    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

__slots__ class-attribute instance-attribute

__slots__ = ('_fuse', '_iter', '_predicate')

__init__

__init__(
    __iterable: Iterable[T_co],
    predicate: Callable[[T_co], object],
) -> None
Source code in src/iterum/_iterum.py
def __init__(
    self,
    __iterable: Iterable[T_co],
    predicate: Callable[[T_co], object],
    /,
) -> None:
    self._iter = iterum(__iterable)
    self._predicate = predicate
    self._fuse = True

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/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

    @override
    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

__slots__ class-attribute instance-attribute

__slots__ = ('_iter', '_step')

__init__

__init__(__iterable: Iterable[T_co], step: int) -> None
Source code in src/iterum/_iterum.py
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

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/iterum/_iterum.py
class Take(Iterum[T_co]):
    __slots__ = ("_idx", "_iter", "_max")

    def __init__(self, __iterable: Iterable[T_co], n: int, /) -> None:
        self._iter = iterum(__iterable)
        self._max = n
        self._idx = 0

    @override
    def next(self) -> Option[T_co]:
        if self._idx >= self._max:
            return nil

        self._idx += 1
        return self._iter.next()

__slots__ class-attribute instance-attribute

__slots__ = ('_idx', '_iter', '_max')

__init__

__init__(__iterable: Iterable[T_co], n: int) -> None
Source code in src/iterum/_iterum.py
def __init__(self, __iterable: Iterable[T_co], n: int, /) -> None:
    self._iter = iterum(__iterable)
    self._max = n
    self._idx = 0

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/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

    @override
    def next(self) -> Option[T_co]:
        nxt = self._iter.next()
        if nxt.is_some_and(self._predicate):
            return nxt
        return nil

__slots__ class-attribute instance-attribute

__slots__ = ('_iter', '_predicate')

__init__

__init__(
    __iterable: Iterable[T_co],
    predicate: Callable[[T_co], object],
) -> None
Source code in src/iterum/_iterum.py
def __init__(
    self, __iterable: Iterable[T_co], predicate: Callable[[T_co], object], /
) -> None:
    self._iter = iterum(__iterable)
    self._predicate = predicate

next

next() -> Option[T_co]
Source code in src/iterum/_iterum.py
@override
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 src/iterum/_iterum.py
class Zip[U, V](_IterumAdapter[tuple[U, V]]):
    __slots__ = ("_iter",)

    def __init__(self, __iterable: Iterable[U], other: Iterable[V], /) -> None:
        self._iter = zip(__iterable, other, strict=False)

__slots__ class-attribute instance-attribute

__slots__ = ('_iter',)

__init__

__init__(
    __iterable: Iterable[U], other: Iterable[V]
) -> None
Source code in src/iterum/_iterum.py
def __init__(self, __iterable: Iterable[U], other: Iterable[V], /) -> None:
    self._iter = zip(__iterable, other, strict=False)

iterum.Seq

Bases: Diterum[int]

Source code in src/iterum/_seq.py
class Seq(Diterum[int]):
    __slots__ = ("_back", "_dir", "_front", "_step")

    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)

    @override
    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

    @override
    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

    @override
    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)
        )

__slots__ class-attribute instance-attribute

__slots__ = ('_back', '_dir', '_front', '_step')

__init__

__init__(*, start: int, end: int, step: int) -> None
Source code in src/iterum/_seq.py
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)

next

next() -> Option[int]
Source code in src/iterum/_seq.py
@override
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

next_back

next_back() -> Option[int]
Source code in src/iterum/_seq.py
@override
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

len

len() -> int
Source code in src/iterum/_seq.py
@override
def len(self) -> int:
    if self._dir * (self._back - self._front) < 0:
        return 0

    return (self._back + self._step - self._front) // self._step

__repr__

__repr__() -> str
Source code in src/iterum/_seq.py
def __repr__(self) -> str:
    return (
        f"{type(self).__name__}("
        f"start={self._front}"
        f", end={self._back + self._step}"
        f", step={self._step}"
        ")"
    )

__bool__

__bool__() -> bool
Source code in src/iterum/_seq.py
def __bool__(self) -> bool:
    return self.len() != 0

__eq__

__eq__(other: object) -> bool
Source code in src/iterum/_seq.py
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 src/iterum/_seq.py
class InfSeq(Iterum[int]):
    __slots__ = ("_front", "_step")

    def __init__(self, *, start: int, step: int) -> None:
        self._front = start
        self._step = step

    @override
    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) -> Literal[True]:
        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)

__slots__ class-attribute instance-attribute

__slots__ = ('_front', '_step')

__init__

__init__(*, start: int, step: int) -> None
Source code in src/iterum/_seq.py
def __init__(self, *, start: int, step: int) -> None:
    self._front = start
    self._step = step

next

next() -> Option[int]
Source code in src/iterum/_seq.py
@override
def next(self) -> Option[int]:
    nxt = Some(self._front)
    self._front += self._step
    return nxt

__repr__

__repr__() -> str
Source code in src/iterum/_seq.py
def __repr__(self) -> str:
    return f"{type(self).__name__}(start={self._front}, step={self._step})"

__bool__

__bool__() -> Literal[True]
Source code in src/iterum/_seq.py
def __bool__(self) -> Literal[True]:
    return True

__eq__

__eq__(other: object) -> bool
Source code in src/iterum/_seq.py
def __eq__(self, other: object) -> bool:
    if not isinstance(other, InfSeq):
        return NotImplemented
    return (self._front == other._front) and (self._step == other._step)