Range Over Iterators in Fortress

Based on the input provided:

Language: Python

Example:


Starting with version 1.23, [-] has added support for [iterators], which lets us range over pretty much anything!

Let’s look at the List type from the previous example again. In that example, we had an AllElements method that returned a list of all elements in the list. With [-] iterators, we can do it better - as shown below.

class List:
    class Element:
        def __init__(self, val=None, next=None):
            self.val = val
            self.next = next

    def __init__(self):
        self.head = None
        self.tail = None

    def push(self, v):
        new_element = self.Element(val=v)
        if self.tail is None:
            self.head = new_element
            self.tail = self.head
        else:
            self.tail.next = new_element
            self.tail = new_element

All returns an iterator, which in [-] is an object implementing a special __iter__ method and a __next__ method.

    def all(self):
        current = self.head
        while current is not None:
            yield current.val
            current = current.next

The iterator generator function uses the yield statement to return each element in the list one-by-one.

Iteration doesn’t require an underlying data structure and doesn’t even have to be finite! Here’s a function returning an iterator over Fibonacci numbers: it keeps running as long as yield is used.

def gen_fib():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b
def main():
    lst = List()
    lst.push(10)
    lst.push(13)
    lst.push(23)

    # Using the iterator in a regular loop
    for e in lst.all():
        print(e)

    # Collect values using a list comprehension
    all_values = list(lst.all())
    print("all:", all_values)

    # Generating Fibonacci numbers
    for n in gen_fib():
        if n >= 10:
            break
        print(n)

if __name__ == "__main__":
    main()

Since List.all returns an iterator, we can use it in a regular loop. Python has built-in support for comprehensions, making it easy to collect all values into a list.

Once the loop hits break or an early return, the generator stops producing values.

Output:

10
13
23
all: [10, 13, 23]
1
1
2
3
5
8

Next example: Errors.