Я думаю, что вас смущает функция proper tail call lua.
Чтобы понять это, мы изменяем вашу функцию locals
, позволяя ей принимать один аргумент в качестве стека уровней, используемого при вызове debug.getlocal
. (Я использую Lua 5.3.3)
-- Get local variables with stack level 'level'.
function locals(level)
local variables = {}
local idx = 1
while true do
local ln, lv = debug.getlocal(level, idx)
if ln ~= nil then
variables[ln] = lv
else
break
end
idx = 1 + idx
end
return variables
end
Затем мы изменяем свои функции тестирования, добавляя тот же аргумент, и добавить test3
функции для справки.
function test1(level)
local v = 'I am a local!'
return locals(level)
end
function test2(level)
local v = 'I am a local!'
return (locals(level))
end
function test3(level)
local v = 'I am a local!'
local a = locals(level)
return a
end
Наконец, мы добавляем код для запуска тестов.
local function printTable(t)
-- print(t)
for k, v in pairs(t) do
print(string.format("key = %s, val = %s.", k, v))
end
end
for level = 1, 3 do
print("==== Stack level: " .. tostring(level))
for num = 1, 3 do
print(string.format("What test%d returns: ", num))
printTable(_G[(string.format("test%d", num))](level))
print("")
end
end
В приведенном выше коде используются тестовые функции с различным уровнем стека и печать возвращаемых пар ключ-значение. Мой результат выглядит следующим образом:
==== Stack level: 1
What test1 returns:
key = variables, val = table: 0x7fa14bc081e0.
key = idx, val = 3.
key = level, val = 1.
What test2 returns:
key = variables, val = table: 0x7fa14bc08220.
key = idx, val = 3.
key = level, val = 1.
What test3 returns:
key = variables, val = table: 0x7fa14bc088b0.
key = idx, val = 3.
key = level, val = 1.
==== Stack level: 2
What test1 returns:
key = (for step), val = 1.
key = (for limit), val = 3.
key = (for index), val = 1.
key = level, val = 2.
key = printTable, val = function: 0x7fa14bc08360.
key = (*temporary), val = function: 0x7fa14bc08360.
key = num, val = 1.
What test2 returns:
key = level, val = 2.
key = v, val = I am a local!.
What test3 returns:
key = level, val = 2.
key = v, val = I am a local!.
==== Stack level: 3
What test1 returns:
key = (*temporary), val = function: 0x109f5a070.
What test2 returns:
key = (for step), val = 1.
key = (for limit), val = 3.
key = (for index), val = 2.
key = level, val = 3.
key = printTable, val = function: 0x7fa14bc08360.
key = (*temporary), val = function: 0x7fa14bc08360.
key = num, val = 2.
What test3 returns:
key = (for step), val = 1.
key = (for limit), val = 3.
key = (for index), val = 3.
key = level, val = 3.
key = printTable, val = function: 0x7fa14bc08360.
key = (*temporary), val = function: 0x7fa14bc08360.
key = num, val = 3.
Когда level
является 1, locals
работает хорошо, чтобы дать свои собственные локальные переменные. Но когда level
равно 2, test1
возвращает переменные внешнего объема, тогда как test2
и test3
дают ожидаемый результат. Для уровня стека 3 test2
и test3
верните что-то вроде test1
на уровне стека 2. Таким образом, кажется, test1
пропускает уровень стека, и единственным объяснением, о котором я мог думать, является правильный хвостовой вызов.
В соответствии с PIL (ссылка, которую я предоставляю в начале) правильный хвостовой вызов никогда не вызовет переполнение стека, которое я принимаю при выполнении вызова в некотором встроенных способах. Если я прав, это объясняет пропущенное поведение оператора возврата test1
, потому что это правильный хвостовой вызов и единственный в трех тестовых функциях.
Мне нравится ваша методология! Огромное спасибо. – yawn
Я не уверен, как отправлять комментарии в комментариях, но, похоже, это скорее вызовы хвоста, так как обертывание locals (2) с помощью функции идентификации работает, что, если предположить, что он работает, как в Scheme, должно быть достаточно, чтобы отключить оптимизация хвостовых вызовов. Я предполагаю, что, поскольку круглые скобки выполняют некоторую форму вычислений в Lua (возвращают только первое из нескольких значений), то их должно быть достаточно, чтобы отключить TCO – yawn