subfunctions in vim - function

I created a lot of functions in menu.vim.
I noted that in many functions the same code is used that's why I decided to clean up my file with the use of
subfunctions.
p.e this is code what often returns in my functions:
let zoek = #/
if a:type == "'<,'>"
let r = substitute(zoek, '\\%V', '', 'g')
elseif a:type == "%"
let r = zoek
endif
let a = substitute(r, '\', '', 'g')
if matchstr(d, '>') == '>' || matchstr(d, '<') == '<'
let e = substitute(d, '\zs>\(\d\+\)%<\ze', '\1-', 'g')
endif
How can I create a subfunction from it? How can I invoke it?
Does Vim have subfunctions?

You can have «local» functions by defining them in the dictionary: in the following code
function MyFunc()
let d={}
function d.function()
echo "Foo"
endfunction
call d.function()
endfunction
function d.function is accessible only inside s:MyFunc and is destroyed after s:MyFunc exits. I put «local» in quotes because d.function is really global function named 42 (or another number, it does not matter). It cannot be called without a reference to it and the only way to create a reference is to use function dict.key() (references may be copied after creation, but you can't create a reference using call to function(), though it is possible for MyFunc: function("MyFunc")). Note that number (in this case 42) is incremented each time you create a function and I know neither what is the maximum number nor what will happen when it will be reached. I personally use dictionary functions because they have two other advantages:
Dictionary function defined inside a script-local dictionary cannot be reached without a debugger or explicit passing the function reference (possibly as a part of its container) somewhere.
If more then one function is defined inside a dictionary in order to purge them all you need is to unlet this dictionary. Useful for reloading plugins.

There is only one type of function in Vimscript, but I'm not sure if this is what you are already using in your menu.vim. A user-defined function is defined thus:
function! MyNewFunction()
" your code here
endfunction
You can then call this function elsewhere in your scripts (and inside other functions) using
call MyNewFunction()
Or set a variable equal to the return value of your function using
let my_variable = MyNewFunction()
Of course this is an incredibly simplistic overview, since you say your are already using functions. Much more information, including the use of variables, here:
help user-functions
Apologies if I have not answered your question.

Related

Retrieving A Function From A WebhookScript Global Variable

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)

How to pass an object as argument to an anonymous function in MATLAB?

I'm working on a MATLAB app that programatically creates anonymous functions to evaluate any native MATLAB function and pass it a list of variables as argument. In the example below, 'formula' contains a string with the function and arguments to be evaluated (e.g., "sum( var1, var2 )" ). The formulas sometimes contain function calls nested within function calls, so the code below would be used recursively until obtaining the final result:
Func2 = str2func( sprintf( '#(%s) %s', strjoin( varNames, ',' ), formula ) );
This evaluates fine for native MATLAB functions. But there's a particular case of a function (named Func1) I made myself that not only needs the list of variables but also an object as argument, like this:
function output = Func1( anObject, varNames )
% do some stuff with the object and the vars
end
For this particular function, I've tried doing this:
Func2 = str2func( sprintf( '#(%s,%s) %s', "objectToPassToFunc1", strjoin( varNames, ',' ), "Func1(objectToPass,""" + strjoin( varNames, '","' ) +""")" ) )
...which doesn't throw an error, but Func1 doesn't receive the objectToPassToFunc1, instead it gets values from one of the variables in varNames. And I don't know why.
So how can I correctly pass the object to Func1????
Matlab doesn't care about the type of arguments you pass to a function. As a matter of fact, the input could be scalar, vector, matrix, and even an object of a class. See the following example.
classdef ClassA
methods
function print(~)
disp('method print() is called.');
end
end
end
This class has only one method. Now, let us define an anonymous function func which accepts one input.
func = #(arg) arg.print;
Notice that we explicitly assume that the input is an object of ClassA. If you pass another type of data to this function, Matlab will throw an error. To test the code,
obj = ClassA;
func = #(arg) arg.print;
func(obj)
To avoid the error, you may need to check the type of the input before using it. For example,
function [] = func(arg)
% check if arg is an object of ClassA
if isa(arg,'ClassA')
arg.print;
end
end
Now you can pass different types for the input without getting an error.

How to remove duplicate results from a cts:uris when distinct values does not work

I have the following code that returns an array of array of results I try to use distinct-values to remove duplicates and it does nothing I have tried also removing using looping functions by comparing values with no success.
I have tried converting to "xs anyAtomicType" and using distinct values
I have tried putting in json array and extracting the sub-array
I have tried tokenizing, xdmp quote, string-before/after and many others
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
I get back duplicated result in form of:
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
I am expecting:
/users/123-343-/profile.xml
/users/122-222-/profile.xml
Is it possible that you have simply invoked this function 3 times and didn't realize it?
You have declared $dir to be a single xs:string. If your $dir happened to be a sequence of strings of the same directory, or if you otherwise invoked the function 3 times with the directory variable.
It can easily happen with function mapping enabled (default behavior). https://docs.marklogic.com/guide/xquery/enhanced#id_55459
There are a couple of things that you can do as a diagnostic:
1.) Remove the explicit type on the $dir parameter in the function:
declare function local:verify-user-uri($dir)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
do you get an error executing cts:uris() that looks like this:
[1.0-ml] XDMP-ARGTYPE: )err:XPT0004) cts:uris(("/users/", "/users/", "/users/"), ()) -- arg1 is not of type xs:string?
2.) try disabling function mapping by adding the following to the prolog:
declare option xdmp:mapping "false";
and see if you then get an invalid coercion error like:
[1.0-ml] XDMP-AS (err:XPTY0004) $dir as xs:string -- Invalid coersion ("/users/", "/users/", "/users/") as xs:string
3.) You could also add something to the end of the sequence of values returned from the function to indicate how many times it has executed:
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds, "#"
};
And see how many times you see "#" in the result. If more than one, you are invoking the function multiple times.
Next to the good suggestions from Mads, I notice a couple of other things about your code:
It doesn't make sense to iterate over $each as it contains one uri only. Keep in mind that a FLWOR statement ends with a return, which tells what should be the result per item
Beware that the first arg to cts:uris only marks a start, not an end. If you feed in /aaa/, you also get back /bbb/ etc, though not vice versa.
To be honest, I think you are looking for cts:uri-match() instead, which would reduce your function to a one-liner:
declare function local:verify-user-uri($dir as xs:string) {
cts:uri-match($dir || "*/profile.xml")
};
HTH!
PS: I do recommend always disabling function mapping as Mads recommends. It can prevent a lot of confusion.

lua not modifying function arguments

I've been learning lua and can't seem to make a simple implementation of this binary tree work...
function createTree(tree, max)
if max > 0 then
tree = {data = max, left = {}, right = {}}
createTree(tree.left, max - 1)
createTree(tree.right, max - 1)
end
end
function printTree(tree)
if tree then
print(tree.data)
printTree(tree.left)
printTree(tree.right)
end
end
tree = {}
createTree(tree, 3)
printTree(tree)
the program just returns nil after execution. I've searched around the web to understand how argument passing works in lua (if it is by reference or by value) and found out that some types are passed by reference (like tables and functions) while others by value. Still, I made the global variable "tree" a table before passing it to the "createTree" function, and I even initialized "left" and "right" to be empty tables inside of "createTree" for the same purpose. What am I doing wrong?
It is probably necessary to initialize not by a new table, but only to set its values.
function createTree(tree, max)
if max > 0 then
tree.data = max
tree.left = {}
tree.right = {}
createTree(tree.left, max - 1)
createTree(tree.right, max - 1)
end
end
in Lua, arguments are passed by value. Assigning to an argument does not change the original variable.
Try this:
function createTree(max)
if max == 0 then
return nil
else
return {data = max, left = createTree(max-1), right = createTree(max-1)}
end
end
It is safe to think that for the most of the cases lua passes arguments by value. But for any object other than a number (numbers aren't objects actually), the "value" is actually a pointer to the said object.
When you do something like a={1,2,3} or b="asda" the values on the right are allocated somewhere dynamically, and a and b only get addresses of those. Thus, when you pass a to the function fun(a), the pointer is copied to a new variable inside function, but the a itself is unaffected:
function fun(p)
--p stores address of the same object, but `p` is not `a`
p[1]=3--by using the address you can
p[4]=1--alter the contents of the object
p[2]=nil--this will be seen outside
q={}
p={}--here you assign address of another object to the pointer
p=q--(here too)
end
Functions are also represented by pointers to them, you can use debug library to tinker with function object (change upvalues for example), this may affect how function executes, but, once again, you can not change where external references are pointing.
Strings are immutable objects, you can pass them around, there is a library that does stuff to them, but all the functions in that library return new string. So once, again external variable b from b="asda" would not be affected if you tried to do something with "asda" string inside the function.

Calling the function name

As a beginner in Lua, I am sorry if the answer on this is easy.
I was trying to call a function within a code, yet after 2 hours of searching I couldn't find the wanted results. (Maybe I use the wrong search query's?)
Example code
function Test123 ()
SayTest = True
if SayTest = True then
-- This Is where I want to call the function name Test123,
-- yet I can't seem to succeed in this since it is just
-- starting a new function
SystemNotice ( role, function)
end
end
This should be the result:
function Test123 ()
SayTest = True
if SayTest = True then
SystemNotice ( role, 'Test123')
end
end
If anyone can help me out, I would be thankful. If I am still being unclear, just tell me and I will try to describe it better. My excuses for my limited English.
In Lua functions are actually values. That means they do not really have a name, you can only assign them to a variable or table field, but since the value itself has no concept of its name, you can't retrieve it.
That said, with the debug library, you can do this:
function getfname()
return debug.traceback("", 2):match("in function '(.-)'");
end
function bar()
print(getfname())
end
bar(); -- prints bar
foo = bar;
foo() -- prints foo
knerf = {rab = bar};
knerf.rab() -- prints rab
Note that this only works with the default Lua error handler or one that returns the same or very similar output, however you can obviously modify the pattern to suit what you need.
Read this: I would not advise this solution for performance-intensive tasks. Both string matching and the traceback are not really suited for this. Also, obviously the debug library must be enabled so you can actually use the traceback function.
Your function declaration lacks anend.
function Test123 ()
end
Read the functions chapter from the Lua manual. Just for the record, your if will also need an end.
This is a construct that just goes against the Lua philosophy that functions are first class citizens:
a function is just another value, and as such it has no name.
A variable can be assigned a value, thus binding a function to a name.
But that name can change. or a function can have multiple names. Which one to pick?
A better solution would be creating an anonymous function with an upvalue (a closure) instead:
function genTest(name)
return function()
SayTest = true
if SayTest == true then
print ( 'role', name)
end
end
end
Test123 = genTest('Test123')
Test123()
foobar = Test123
foobar()
This creates a function with a bound local variable name (see PiL 6.1 ).