Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass an arbitrary iterator as a function argument?

Tags:

iterator

lua

Question

If I write a generic walk routine, why can I pass in my own iterators but not pairs?

Example

Here's a simple walk that does something for each item in src.

function walk(src)
  for n,i in src do 
    print(n,  i[1]+i[#i]) end end

If I call this with walk(items(x)) then walk works fine.

function items(lst, n)
  n=0
  return function()
    if lst and n < #lst then
      n=n+1
      return n,lst[n] end end end

x={
  {1,2},
  {3,4},
  {5,6},
  {5,6}}

walk(items(x)) --> prints out (1,3),(2,7),(3,11),etc

But I try the same with pairs(x), I get a crash.

walk(pairs(x))
lua: x.lua: bad argument #1 to 'for iterator' (table expected, got nil)
stack traceback:
    [C]: in function 'next'
    x.lua:7: in function 'walk'
    x.lua:31: in main chunk
    [C]: in ?

So what is different about pairs and my own iterator items?

like image 662
Tim Menzies Avatar asked Jun 23 '26 05:06

Tim Menzies


1 Answers

The pairs function returns 3 values:

  1. The next function
  2. The table
  3. The initial key nil

The for-in statement uses the 3 values in an equivalent process as follows:

local f, t, k = pairs(x)
local v

repeat
  k, v = f(t, k)
  if k then
    -- for body
  end
until not k

Since the 3rd value is always nil, if you want the walk function to be effective on pairs, you need at least 2 arguments:

function walk(itor, t)
  for n,i in itor, t do 
    print(n, i[1]+i[#i]) end end

You need 3 if you want it to be effective on any iterator functions.

like image 140
shingo Avatar answered Jun 28 '26 04:06

shingo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!