Iterators

GSL Shell provides a number of simple functions to perform some common tasks related to iterators. These functions allow you to write more simple and compact code and to improve the readability. The functions described below are available in the module iter.

iter.sequence(f, a, b)
iter.sequence(f, b)

Return an “iterator” that gives the value (or the values) returned by the evaluation of f(i) where i is an integer that goes from a to b. In the second form, the generated values start from one.

Generally, an iterator is a function that, each time that it is called, returns one value from a sequence. The sequence is considered to be terminated when the iterator returns nil. An iterator can be used directly in a for loop with the following syntax:

for a, b, ... in f do
   -- [ some code here]
end

where f is the iterator. If f returns multiple values they will be all returned by the iterator.

iter.sample(f, xi, xs, n)

Return an iterator that gives the couple x, f(x) for x going from xi to xs with n uniformly spaced intervals. If f returns multiple values, only the first one is retained.

Example:

-- print (x, sin(x)) for x going from 0 to 2*pi with 16 sampling points
for x, y in sample(sin, 0, 2*pi, 16) do
   print(x, y)
end
iter.isample(f, a, b)
iter.isample(f, b)

Return an iterator that gives the couple i, f(i) where i is an integer going from a to b. In the second form, the sequence will start from one. If f returns multiple values, only the first one is retained.

iter.ilist(f, a, b)
iter.ilist(f, b)

Returns a list with the elements f(i) where i is an integer going from a to b. In the second form, the sequence will start from one.

iter.isum(f, a, b)
iter.isum(f, b)

Returns the sum of f(i) for all integers i from a to b. In the second form, the sequence will start from one.

More complex iterators

Actually the more general form of an iterator is the following:

for i, a, b, ... in f, s, i0 do
   -- [ some code here]
end

In this latter form, the iterator f is called in the form f(s, i), where s is the value provided in the for loop. The value of i changes every time, the value taken is the first value returned by the function f the last times it was called or, for the first time only, i0.

We give an example to build a stateless row “iterator” over the rows of a matrix.:

-- we define the stateless iterator
function my_row_iter(m, i)
   local r, c = dim(m)
   if i <= r then
      return i+1, m:row(i)
   end
end

-- how it can be used
for i, row in my_row_iter, m, 1 do
   print('Row number', i, ':', row)
end

Note that in this case we have to provide the “iterator”, its “state” and the initial “index” value i0 explicitly. You may avoid that by using an “iterator builder” like in the following example:

function make_row_iter(m)
   return my_row_iter, m, 1
end

-- then we can write
for i, row in make_row_iter(m) do
   print('Row number', i, ':', row)
end

To summarize, this example shows how to create an iterator to iterate over the row of a matrix. The iterator builder is a function that returns three values, the first is a function (the iterator itself), the second is the state and the third argument is the first value of the index.