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.