Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the "type signature" of pairs() in Lua?

Tags:

lua

Looking at the chapter 7.1 – Iterators and Closures from "Programming in Lua" it seems like the the for foo in bar loop takes requires bar to be of type (using Java typesto express it) Supplier<Tuple> and the the for-in will keep calling bar until it returns nil.

So for something like:

for k,v in pairs( tables ) do
    print( 'key: '..k..', value: '..v )
end

that implies pairs has a type of Function<Table,Supplier<Tuple>>.

I want to create a function that behaves like pairs except it skips tuples where the first argument starts with an underscore (ie _).

local function mypairs( list )
    local --[[ Supplier<Tuple> ]] pairIterator = pairs( list )
    return --[[ Supplier<Tuple> ]] function ()
        while true do
            local key, value = pairIterator()
            if key == nil then
                return nil
            elseif key:sub(1,1) ~= '_' then
                return key, value
            end
        end
    end
end

however it doesn't work since

--[[should be: Supplier<Table>]] pairIterator = pairs({ c=3; b=2; a=1 })

when I call it

pairIterator()

it returns

stdin:1: bad argument #1 to 'pairIterator' (table expected, got no value)
stack traceback:
    [C]: in function 'pairIterator'
    stdin:1: in main chunk
    [C]: in ?

but

pairIterator({ c=3; b=2; a=1 })

returns

Lua>pairIterator({ c=3; b=2; a=1 })
c       3
like image 991
Sled Avatar asked Nov 26 '25 13:11

Sled


1 Answers

Your basic problem is that you're using Java logic on Lua problems. Java and Lua are different languages with different constructs, and it's important to recognize that.

pairs does not have a return value; it has multiple return values. This is a concept that Java completely lacks. A Tuple is a single value that can store and manipulate multiple values. A Lua function can return multiple values. This is syntactically and semantically distinct from returning a table containing multiple values.

The iterator-based for statement takes multiple values as its input, not a table or container of multiple values. Specifically, it stores 3 values: an iterator function, a state value (which you use to preserve state between calls), and an initial value.

So, if you want to mimic pairs's behavior, you need to be able to store and manipulate its multiple return values.

Your first step is to store what pairs actually returns:

local f, s, var = pairs(list)

You are creating a new iterator function. So you need to return that, but you also need to return the s and var that pairs returns. Your return statement needs to look like this:

return function (s, var)
    --[[Contents discussed below]]
end, s, var --Returning what `pairs` would return.

Now, inside your function, you need to call f with s and var. This function will return the key/value pair. And you need to process them correctly:

return function (s, var)
    repeat
        local key, value = f(s, var)
        if(type(key) ~= "string") then
            --Non-string types can't have an `_` in them.
            --And no need to special-case `nil`.
            return key, value
        elseif(key:sub(1, 1) ~= '_') then
            return key, value
        end
    until true
end, s, var --Returning what `pairs` would return.
like image 58
Nicol Bolas Avatar answered Nov 28 '25 16:11

Nicol Bolas



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!