In WebhookScript, I can store a function in a variable with:
sub = function(a, b) {
return a - b
}
I'd like to store a function in a Global Variable so that I can use it in multiple Custom Actions. But if I've saved the above function as $sub$ then
sub2 = var('$sub$')
subX = sub(1,2)
causes an error:
Trying to invoke a non-function 'string' # line...
And
function subX(a,b){
var('$sub$')
}
when sub only contains return a - b, doesn't work either.
Obviously I need to convert the string to a function but I'm not sure whether that's possible.
I know this is a bit of an obscure language but if anyone knows how this can be done in similar languages like JavaScript and PHP, I'm happy to test out any guesses...
The solution here is to remove the function section and just enter the script, which inherits the execution scope so if my global variable $script$ is:
return 'hello ' + a
Then I can execute the function with:
a = 'world'
value = exec(var('$script$'))
echo(value)
(credit to Webhook.Site's support team for explaining this)
function [TC]=Translate(T0,Base)
end
I know that Translate is a function and T0 and Base his parameter but what is [TC]?
Octave (and matlab) have a rather unique way of returning variables from functions. Instead of defining explicitly what to return from the function using a return keyword, they define from the outset which variables will be returned when the function exits, and octave simply looks for those variables by name at the time the function exits, and returns their values, whatever they may be by that point.
Your function may return nothing:
function returnsNothing();
disp('hello, I return nothing');
end
or it may return one output:
function Out = returnsOne(x)
Out = x+5
disp('This function will return the value of Out');
end
or it may return more than one outputs:
function [Out1, Out2] = returnsTwo(x)
Out1 = x+5;
Out2 = x+10;
end
You would call the last function from the octave terminal (or script) like this:
[a,b] = returnsTwo(5); % this will make a = 10 and b = 15
I just started learning lua, so what I'm asking might be impossible.
Now, I have a method that accepts a function:
function adjust_focused_window(fn)
local win = window.focusedwindow()
local winframe = win:frame()
local screenrect = win:screen():frame()
local f, s = fn(winframe, screenrect)
win:setframe(f)
end
I have several functions that accept these frames and rectangles (showing just one):
function full_height(winframe, screenrect)
print ("called full_height for " .. tostring(winframe))
local f = {
x = winframe.x,
y = screenrect.y,
w = winframe.w,
h = screenrect.h,
}
return f, screenrect
end
Then, I can do the following:
hotkey.bind(scmdalt, '-', function() adjust_focused_window(full_width) end)
Now, how could I compose several functions to adjust_focused_window, without changing it's definition. Something like:
hotkey.bind(scmdalt, '=', function() adjust_focused_window(compose(full_width, full_height)) end)
where compose2 would return a function that accepts the same parameters as full_width and full_height, and internally does something like:
full_height(full_width(...))
As mentioned in the comments, to chain two functions together you can just do:
function compose(f1, f2)
return function(...) return f1(f2(...)) end
end
But what if you want to connect more than 2 functions together? You might ask, is it possible to 'compose' an arbitrary number of functions together?
The answer is a definite yes -- below I show 3 different approaches for implementing this plus a quick summary of their consequences.
Iterative Table approach
The idea here is to call each function in the list one after the other in turn. While doing so, you save the returned results from the previous call into a table and you unpack that table and pass it into the next call.
function compose1(...)
local fnchain = check_functions {...}
return function(...)
local args = {...}
for _, fn in ipairs(fnchain) do
args = {fn(unpack(args))}
end
return unpack(args)
end
end
The check_functions helper above just checks that the stuff passed in are indeed functions -- raises an error if not. Implementation omitted for brevity.
+: Reasonably straight-forward approach. Probably what you'd come up with on a first attempt.
-: Not very efficient on resources. A lot of garbage tables to store results between calls. You also have to deal with packing and unpacking the results.
Y-Combinator Pattern
The key insight here is that even though the functions we're calling isn't recursive, it can be made recursive by piggy-backing it on a recursive function.
function compose2(...)
local fnchain = check_functions {...}
local function recurse(i, ...)
if i == #fnchain then return fnchain[i](...) end
return recurse(i + 1, fnchain[i](...))
end
return function(...) return recurse(1, ...) end
end
+: Doesn't create extra temporary tables like above. Carefully written to be tail-recursive -- that means no extra stack space needed for calls to long function chains. There's a certain elegance to it.
Meta-script generation
With this last approach, you use a lua function that actually generates the exact lua code that performs the function call chain desired.
function compose3(...)
local luacode =
[[
return function(%s)
return function(...)
return %s
end
end
]]
local paramtable = {}
local fcount = select('#', ...)
for i = 1, fcount do
table.insert(paramtable, "P" .. i)
end
local paramcode = table.concat(paramtable, ",")
local callcode = table.concat(paramtable, "(") ..
"(...)" .. string.rep(')', fcount - 1)
luacode = luacode:format(paramcode, callcode)
return loadstring(luacode)()(...)
end
The loadstring(luacode)()(...) probably needs some explaining. Here I chose to encode the function chain as parameter names (P1, P2, P3 etc.) in the generated script. The extra () parenthesis is there to 'unwrap' the nested functions so the inner most function is what's returned. The P1, P2, P3 ... Pn parameters become captured upvalues for each of the functions in the chain eg.
function(...)
return P1(P2(P3(...)))
end
Note, you could also have done this using setfenv but I chose this route just to avoid the breaking change between lua 5.1 and 5.2 on how function environments are set.
+: Avoids extra intermediate tables like approach #2. Doesn't abuse the stack.
-: Needs an extra byte-code compile step.
You can iterate through the passed functions, successively invoking the next function in the chain with the results from the previous.
function module._compose(...)
local n = select('#', ...)
local args = { n = n, ... }
local currFn = nil
for _, nextFn in ipairs(args) do
if type(nextFn) == 'function' then
if currFn == nil then
currFn = nextFn
else
currFn = (function(prev, next)
return function(...)
return next(prev(...))
end
end)(currFn, nextFn)
end
end
end
return currFn
end
Note the use of Immediately Invoked Function Expressions above, which allow the re-used function variables to not invoke an infinite recursive loop, which happens in the following code:
function module._compose(...)
local n = select('#', ...)
local args = { n = n, ... }
local currFn = nil
for _, nextFn in ipairs(args) do
if type(nextFn) == 'function' then
if currFn == nil then
currFn = nextFn
else
currFn = function(...)
return nextFn(currFn(...)) -- this will loop forever, due to closure
end
end
end
end
return currFn
end
Although Lua doesn't support ternary operators, short-circuit evaluation can be used to remove the inner if statement:
function module.compose(...)
local n = select('#', ...)
local args = { n = n, ... }
local currFn = nil
for _, nextFn in ipairs(args) do
if type(nextFn) == 'function' then
currFn = currFn and (function(prev, next)
return function(...)
return next(prev(...))
end
end)(currFn, nextFn) or nextFn
end
end
return currFn
end
In Lua, is it possible to know which function has called the current function.
For instance
function a()
get_calling_function() --Should print function b
end
function b()
a()
end
Is something like this possible?
Does the debug library have such functionality?
You could use debug.traceback():
function a()
print(debug.traceback())
end
function b()
a()
end
b()
which would print:
stack traceback:
./test.lua:45: in function 'a'
./test.lua:50: in function 'b'
./test.lua:53: in main chunk
[C]: in ?
you can use debug.sethook() to set up a hook that gets called each time certain special events happen in lua. it can be useful for things like this.
local debugInfo = { caller = nil, callee = nil }
function hook()
local info = debug.getinfo(2)
if info == nil then
debugInfo.callee = nil
return
end
-- we only want to watch lua function calls (not C functions)
if info.what ~= "Lua" then
debugInfo.callee = "C function"
return
end
debugInfo.caller = debugInfo.callee
debugInfo.callee = info.name
end
debug.sethook(hook, "c")
function caller1()
if debugInfo.caller ~= nil and debugInfo.callee ~= nil then
msg = debugInfo.callee.. " was called by ".. debugInfo.caller.. "!"
print(msg)
end
end
function caller2()
caller1()
end
caller2()
this prints 'caller1 was called from caller2!'
debug.sethook can handle 3 different characters in the second parameter so you can let it know when to notify you. 'c' means call your hook function any time a function is called in lua, 'r' means call your hook function every time a function returns in lua, and 'l' means call your hook function whenever lua processes a new line of code.
you could set this up to build your own custom stack trace if you really wanted to, and you could also use debug.getlocal() within your hook to even try to work out what arguments were passed to your called function.
edit for lhf. this is actually a much simpler way of doing what you're asking, if you don't need to track this and just need to know the context of how the function was called.
function caller1()
local current_func = debug.getinfo(1)
local calling_func = debug.getinfo(2)
print(current_func.name.. " was called by ".. calling_func.name.. "!")
end
function caller2()
caller1()
end
I am looking for a more pleasant way to add an argument name while calling a function.
Something which is better than either of these
local ret = foo( --[[argNam1 =]] true)
local ret = foo( true ) -- first argument is argName1
I tried
local ret = foo( argNam1 = true)
but I got error
')' expected near '='
You could use named parameters, if that's what you want. Lua tables are good for imitating that behavior. So instead of passing all parameters separated by a comma, you pass a single table object; that has named keys.
If that is your foo() function:
local foo(parameters)
print(parameters.argNam1)
end
Then you could call it like: local ret = foo{argNam1 = true}
Or call it like this:
local arguments = {
argNam1 = true,
argNam2 = "foobar"
}
local ret = foo(arguments)