Question

Recently, Lee Baldwin showed how to write a generic, variable argument memoize function. I thought it would be better to return a simpler function where only one parameter is required. Here is my total bogus attempt:

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

Obviously, select('#', ...) fails in this context and wouldn't really do what I want anyway. Is there any way to tell inside memoize how many arguments f expects?


"No" is a fine answer if you know for sure. It's not a big deal to use two separate memoize functions.

Was it helpful?

Solution

I guess you could go into the debug info and determine this from the source-code, but basically it's a "no", sorry.

OTHER TIPS

Yes, for Lua functions but not C functions. It's a bit torturous and a little sketchy.

debug.getlocal works on called functions so you have to call the function in question. It doesn't show any hint of ... unless the call passes enough parameters. The code below tries 20 parameters.

debug.sethook with the "call" event gives an opportunity to intercept the function before it runs any code.

This algorithm works with Lua 5.2. Older versions would be similar but not the same:

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

A little helper iterator (could be inlined for efficiency):

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

Returns the signature (but could return a parameter count and usesVarargs, instead):

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

I'm pretty sure you can't do that in Lua.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top