Есть ли способ определить сигнатуру функции Lua?

Недавно Lee Baldwin показал, как написать универсальную функцию записи переменных в переменные. Я думал, что было бы лучше вернуть более простую функцию, где требуется только один параметр. Вот моя полная фиктивная попытка:

local function memoize(f)
   local cache = {}

   if select('#', ...) == 1 then
      return function (x)
                if cache[x] then
                   return cache[x]
                else
                   local y = f(x)
                   cache[x] = y
                   return y
                end
              end
   else
      return function (...)
                local al = varg_tostring(...)
                if cache[al] then
                   return cache[al]
                else
                   local y = f(...)
                   cache[al] = y
                   return y
                end
             end
   end
end

Очевидно, чтоselect('#', ...) терпит неудачу в этом контексте и не будет действительно делать то, что я хочу в любом случае. Есть ли какой-нибудь способ сказать внутри, запомни, сколько аргументов ожидает?


"Нет" - хороший ответ, если вы точно знаете. Нет ничего страшного в использовании двух отдельных функций памятки.

3 ответа

Решение

Я полагаю, вы могли бы перейти к отладочной информации и определить это по исходному коду, но в основном это "нет", извините.

Да, для функций Lua, но не для функций C. Это немного мучительно и немного схематично.

debug.getlocal работает с вызываемыми функциями, поэтому вы должны вызвать соответствующую функцию. Это не показывает ни намека на ... если вызов не передает достаточно параметров. Код ниже пытается 20 параметров.

debug.sethook событие "call" дает возможность перехватить функцию, прежде чем она запустит какой-либо код.

Этот алгоритм работает с Lua 5.2. Старые версии будут похожи, но не одинаковы:

assert(_VERSION=="Lua 5.2", "Must be compatible with Lua 5.2")

Небольшой вспомогательный итератор (может быть встроен для эффективности):

local function getlocals(l)
  local i = 0
  local direction = 1
  return function ()
    i = i + direction
    local k,v = debug.getlocal(l,i)
    if (direction == 1 and (k == nil or k.sub(k,1,1) == '(')) then 
      i = -1 
      direction = -1 
      k,v = debug.getlocal(l,i) 
    end
    return k,v
  end
end

Возвращает подпись (но может возвратить счетчик параметров и использует вместо этого Varargs):

local function dumpsig(f)
  assert(type(f) == 'function', 
    "bad argument #1 to 'dumpsig' (function expected)")
  local p = {}
  pcall (function() 
    local oldhook
    local hook = function(event, line)
      for k,v in getlocals(3) do 
        if k == "(*vararg)" then 
          table.insert(p,"...") 
          break
        end 
        table.insert(p,k) end
      debug.sethook(oldhook)
      error('aborting the call')
    end
    oldhook = debug.sethook(hook, "c")
    -- To test for vararg must pass a least one vararg parameter
    f(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
  end)
  return "function("..table.concat(p,",")..")"  
end

Я почти уверен, что вы не можете сделать это в Lua.

Другие вопросы по тегам