Understanding how to pass macro arguments to a program in Stata - global-variables

I am currently writing a short program to print the global macro variables of the current Stata session.
I cannot understand the outcome of the following piece of code:
macro drop _all
global glob0: all globals
cap program drop print_globals
program define print_globals
args start_globs
di "$glob0"
di "`start_globs'"
end
print_globals $glob0
The outcome of this is:
S_level S_ADO S_StataMP S_StataSE S_FLAVOR S_OS S_OSDTL S_MACH
S_level
Why am I not passing to start globs the entire information contained in glob0?

Your args statement assigns only the first argument supplied to the program to a local macro; if there are other arguments they are ignored.
The essence of the matter is whether double quotes are used to bind what is supplied into one argument.
Whether you supply an argument as a global or a local is immaterial: globals and locals mentioned on the command line are evaluated before the program even runs and are not seen as such; only their contents are passed to the program.
Define this simpler program and run through the possibilities:
program showfirstarg
args first
di "`first'"
end
global G "A B C D E"
local L "A B C D E"
showfirstarg $G
showfirstarg "$G"
showfirstarg `L'
showfirstarg "`L'"
Results in turn:
. showfirstarg $G
A
. showfirstarg "$G"
A B C D E
. showfirstarg `L'
A
. showfirstarg "`L'"
A B C D E

In order to print the content of the program argument as intended, one must use compound quotes:
print_globals `" ${glob0} "'
and not print_globals ${glob0}.
To see this, consider the following example:
local A "a b c d e"
global B "a b c d e"
cap program drop print_prog
program define print_prog
args loc_input
di "print global: $B"
di "print local: `loc_input'"
end
print_prog `A'
print_prog `" `A' "' // prints both A and B as initially intended
The confusion here is given by the fact that B is printed as intended without having to use compound quotes, whereas the same does not apply for the local macro A when it's passed as argument to the program.
In fact, as highligted in the comments below, in the latter case only the first element is passed as program argument (a in the example).
By using compound quotes we supply a b c d e as a single argument and the final result is the one wanted.

Related

Refer to struct fields without dot notation (in Julia)

In Julia I've defined a type and I need to write some functions that work with the fields of that type. Some of the functions contain complicated formulas and it gets messy to use the field access dot notation all over the place. So I end up putting the field values into local variables to improve readability. It works fine, but is there some clever way to avoid having to type out all the a=foo.a lines or to have Julia parse a as foo.a etc?
struct Foo
a::Real
b::Real
c::Real
end
# this gets hard to read
function bar(foo::Foo)
foo.a + foo.b + foo.c + foo.a*foo.b - foo.b*foo.c
end
# this is better
function bar(foo::Foo)
a = foo.a
b = foo.b
c = foo.c
a + b + c + a*b - b*c
end
# this would be great
function bar(foo::Foo)
something clever
a + b + c + a*b - b*c
end
Because Julia generally encourages the use of generalized interfaces to interact with fields rather than accessing the fields directly, a fairly natural way of accomplishing this would be unpacking via iteration. In Julia, objects can be "unpacked" into multiple variables by iteration:
julia> x, y = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> x
1
julia> y
2
We can implement such an iteration protocol for a custom object, like Foo. In v0.7, this would look like:
Base.iterate(foo::Foo, state = 1) = state > 3 ? nothing : (getfield(foo, state), state + 1)
Note that 3 is hardcoded (based on the number of fields in Foo) and could be replaced with fieldcount(Foo). Now, you can simply "unpack" an instance of Foo as follows:
julia> a, b, c = Foo("one", 2.0, 3)
Foo("one", 2.0, 3)
julia> a
"one"
julia> b
2.0
julia> c
3
This could be the "something clever" at the beginning of your function. Additionally, as of v0.7, you can unpack the fields in the function argument itself:
function bar((a, b, c)::Foo)
a + b + c + a*b - b*c
end
Although this does require that you mention the field names again, it comes with two potential advantages:
In the case that your struct is refactored and the fields are renamed, all code accessing the fields will remain intact (as long as the field order doesn't change or the iterate implementation is changed to reflect the new object internals).
Longer field names can be abbreviated. (i.e. rather than using the full apples field name, you can opt to use a.)
If it's important that the field names not be repeated, you could define a macro to generate the required variables (a = foo.a; b = foo.b; c = foo.c); however, this would likely be more confusing for the readers of your code and lack the advantages listed above.
As of Julia 1.6, the macros in this package look relevant: https://github.com/mauro3/UnPack.jl.
The syntax would look like:
function bar(foo::Foo)
# something clever!
#unpack a, b, c = f
a + b + c + a*b - b*c
end
In Julia 1.7, it looks like this feature will be added with the syntax
function bar(foo::Foo)
# something clever!
(; a, b, c) = f
a + b + c + a*b - b*c
end
Here is the merged pull request: https://github.com/JuliaLang/julia/pull/39285

Evaluate expression with local variables

I'm writing a genetic program in order to test the fitness of randomly generated expressions. Shown here is the function to generate the expression as well a the main function. DIV and GT are defined elsewhere in the code:
function create_single_full_tree(depth, fs, ts)
"""
Creates a single AST with full depth
Inputs
depth Current depth of tree. Initially called from main() with max depth
fs Function Set - Array of allowed functions
ts Terminal Set - Array of allowed terminal values
Output
Full AST of typeof()==Expr
"""
# If we are at the bottom
if depth == 1
# End of tree, return function with two terminal nodes
return Expr(:call, fs[rand(1:length(fs))], ts[rand(1:length(ts))], ts[rand(1:length(ts))])
else
# Not end of expression, recurively go back through and create functions for each new node
return Expr(:call, fs[rand(1:length(fs))], create_single_full_tree(depth-1, fs, ts), create_single_full_tree(depth-1, fs, ts))
end
end
function main()
"""
Main function
"""
# Define functional and terminal sets
fs = [:+, :-, :DIV, :GT]
ts = [:x, :v, -1]
# Create the tree
ast = create_single_full_tree(4, fs, ts)
#println(typeof(ast))
#println(ast)
#println(dump(ast))
x = 1
v = 1
eval(ast) # Error out unless x and v are globals
end
main()
I am generating a random expression based on certain allowed functions and variables. As seen in the code, the expression can only have symbols x and v, as well as the value -1. I will need to test the expression with a variety of x and v values; here I am just using x=1 and v=1 to test the code.
The expression is being returned correctly, however, eval() can only be used with global variables, so it will error out when run unless I declare x and v to be global (ERROR: LoadError: UndefVarError: x not defined). I would like to avoid globals if possible. Is there a better way to generate and evaluate these generated expressions with locally defined variables?
Here is an example for generating an (anonymous) function. The result of eval can be called as a function and your variable can be passed as parameters:
myfun = eval(Expr(:->,:x, Expr(:block, Expr(:call,:*,3,:x) )))
myfun(14)
# returns 42
The dump function is very useful to inspect the expression that the parsers has created. For two input arguments you would use a tuple for example as args[1]:
julia> dump(parse("(x,y) -> 3x + y"))
Expr
head: Symbol ->
args: Array{Any}((2,))
1: Expr
head: Symbol tuple
args: Array{Any}((2,))
1: Symbol x
2: Symbol y
typ: Any
2: Expr
[...]
Does this help?
In the Metaprogramming part of the Julia documentation, there is a sentence under the eval() and effects section which says
Every module has its own eval() function that evaluates expressions in its global scope.
Similarly, the REPL help ?eval will give you, on Julia 0.6.2, the following help:
Evaluate an expression in the given module and return the result. Every Module (except those defined with baremodule) has its own 1-argument definition of eval, which evaluates expressions in that module.
I assume, you are working in the Main module in your example. That's why you need to have the globals defined there. For your problem, you can use macros and interpolate the values of x and y directly inside the macro.
A minimal working example would be:
macro eval_line(a, b, x)
isa(a, Real) || (warn("$a is not a real number."); return :(throw(DomainError())))
isa(b, Real) || (warn("$b is not a real number."); return :(throw(DomainError())))
return :($a * $x + $b) # interpolate the variables
end
Here, #eval_line macro does the following:
Main> #macroexpand #eval_line(5, 6, 2)
:(5 * 2 + 6)
As you can see, the values of macro's arguments are interpolated inside the macro and the expression is given to the user accordingly. When the user does not behave,
Main> #macroexpand #eval_line([1,2,3], 7, 8)
WARNING: [1, 2, 3] is not a real number.
:((Main.throw)((Main.DomainError)()))
a user-friendly warning message is provided to the user at parse-time, and a DomainError is thrown at run-time.
Of course, you can do these things within your functions, again by interpolating the variables --- you do not need to use macros. However, what you would like to achieve in the end is to combine eval with the output of a function that returns Expr. This is what the macro functionality is for. Finally, you would simply call your macros with an # sign preceding the macro name:
Main> #eval_line(5, 6, 2)
16
Main> #eval_line([1,2,3], 7, 8)
WARNING: [1, 2, 3] is not a real number.
ERROR: DomainError:
Stacktrace:
[1] eval(::Module, ::Any) at ./boot.jl:235
EDIT 1. You can take this one step further, and create functions accordingly:
macro define_lines(linedefs)
for (name, a, b) in eval(linedefs)
ex = quote
function $(Symbol(name))(x) # interpolate name
return $a * x + $b # interpolate a and b here
end
end
eval(ex) # evaluate the function definition expression in the module
end
end
Then, you can call this macro to create different line definitions in the form of functions to be called later on:
#define_lines([
("identity_line", 1, 0);
("null_line", 0, 0);
("unit_shift", 0, 1)
])
identity_line(5) # returns 5
null_line(5) # returns 0
unit_shift(5) # returns 1
EDIT 2. You can, I guess, achieve what you would like to achieve by using a macro similar to that below:
macro random_oper(depth, fs, ts)
operations = eval(fs)
oper = operations[rand(1:length(operations))]
terminals = eval(ts)
ts = terminals[rand(1:length(terminals), 2)]
ex = :($oper($ts...))
for d in 2:depth
oper = operations[rand(1:length(operations))]
t = terminals[rand(1:length(terminals))]
ex = :($oper($ex, $t))
end
return ex
end
which will give the following, for instance:
Main> #macroexpand #random_oper(1, [+, -, /], [1,2,3])
:((-)([3, 3]...))
Main> #macroexpand #random_oper(2, [+, -, /], [1,2,3])
:((+)((-)([2, 3]...), 3))
Thanks Arda for the thorough response! This helped, but part of me thinks there may be a better way to do this as it seems too roundabout. Since I am writing a genetic program, I will need to create 500 of these ASTs, all with random functions and terminals from a set of allowed functions and terminals (fs and ts in the code). I will also need to test each function with 20 different values of x and v.
In order to accomplish this with the information you have given, I have come up with the following macro:
macro create_function(defs)
for name in eval(defs)
ex = quote
function $(Symbol(name))(x,v)
fs = [:+, :-, :DIV, :GT]
ts = [x,v,-1]
return create_single_full_tree(4, fs, ts)
end
end
eval(ex)
end
end
I can then supply a list of 500 random function names in my main() function, such as ["func1, func2, func3,.....". Which I can eval with any x and v values in my main function. This has solved my issue, however, this seems to be a very roundabout way of doing this, and may make it difficult to evolve each AST with each iteration.

How to handle a named parameter and #keyword in robotframework

I use the Robot framework with Python and Linux.
I don't know how to use the optional named parameter b and c in the decorator. Can somebody explain?
See example below:
#keyword('Starting a "${a}" b "${b}"?? c "${c}"??')
def Start(self, a, b='', c=''):
foo
The way I understand your question, you're trying to create a keyword with embedded arguments, which would have default args - and this is not allowed, doc link, the last paragraph in Basic Syntax.
What you could do is to leave up for the caller to pass on "the default" values; e.g.:
#keyword('Starting a "${a}" b "${b}" c "${c}"')
def Start(self, a, b, c):
# just work with a, b, c, they *always* have _some_ value when called from RF
foo
# later on, used in Robotframework code:
Starting a "" b "" c ""
When called like this ^, the variables a, b and c will be passed to the python function as empty strings - RF defaults arguments to string type, meaning this code inside the function will work in this case:
assert a == '' # will pass when called with no value for a
assert type(b) == str # this will always work, regardless did b (or a, or c) have a value set in the call, or not

Pass function arguments into Julia non-interactively

I have a Julia function in a file. Let's say it is the below. Now I want to pass arguments into this function. I tried doing
julia filename.jl randmatstat(5)
but this gives an error that '(' token is unexpected. Not sure what the solution would be. I am also a little torn on if there is a main function / how to write a full solution using Julia. For example what is the starting / entry point of a Julia Program?
function randmatstat(t)
n = 5
v = zeros(t)
w = zeros(t)
for i = 1:t
a = randn(n,n)
b = randn(n,n)
c = randn(n,n)
d = randn(n,n)
P = [a b c d]
Q = [a b; c d]
v[i] = trace((P.'*P)^4)
w[i] = trace((Q.'*Q)^4)
end
std(v)/mean(v), std(w)/mean(w)
end
Julia doesn't have an "entry point" as such.
When you call julia myscript.jl from the terminal, you're essentially asking julia to execute the script and exit. As such, it needs to be a script. If all you have in your script is a function definition, then it won't do much unless you later call that function from your script.
As for arguments, if you call julia myscript.jl 1 2 3 4, all the remaining arguments (i.e. in this case, 1, 2, 3 and 4) become an array of strings with the special name ARGS. You can use this special variable to access the input arguments.
e.g. if you have a julia script which simply says:
# in julia mytest.jl
show(ARGS)
Then calling this from the linux terminal will give this result:
<bashprompt> $ julia mytest.jl 1 two "three and four"
UTF8String["1","two","three and four"]
EDIT: So, from what I understand from your program, you probably want to do something like this (note: in julia, the function needs to be defined before it's called).
# in file myscript.jl
function randmatstat(t)
n = 5
v = zeros(t)
w = zeros(t)
for i = 1:t
a = randn(n,n)
b = randn(n,n)
c = randn(n,n)
d = randn(n,n)
P = [a b c d]
Q = [a b; c d]
v[i] = trace((P.'*P)^4)
w[i] = trace((Q.'*Q)^4)
end
std(v)/mean(v), std(w)/mean(w)
end
t = parse(Int64, ARGS[1])
(a,b) = randmatstat(t)
print("a is $a, and b is $b\n")
And then call this from your linux terminal like so:
julia myscript.jl 5
You can try running like so:
julia -L filename.jl -E 'randmatstat(5)'
Add the following to your Julia file:
### original file
function randmatstat...
...
end
### new stuff
if length(ARGS)>0
ret = eval(parse(join(ARGS," ")))
end
println(ret)
Now, you can run:
julia filename.jl "randmatstat(5)"
As attempted originally. Note the additional quotes added to make sure the parenthesis don't mess up the command.
Explanation: The ARGS variable is defined by Julia to hold the parameters to the command running the file. Since Julia is an interpreter, we can join these parameters to a string, parse it as Julia code, run it and print the result (the code corresponds to this description).

Check if an argument is a dictionary or not in Tcl

I want have a proc which does something if its' argument is a Tcl 8.5 and above dictionary or not.
I could not find anything straightforward from Tcl dict command.
The code which I could get working is:
proc dict? {dicty} {
expr { [catch { dict info $dicty } ] ? 0 : 1 }
}
Is there anything w/o using catch, something built in?Thanks.
You can test if a value is a dictionary by seeing if it is a list and if it has an even number of elements; all even length lists may be used as dictionaries (though many are naturally not canonical dictionaries because of things like duplicate keys).
proc is-dict {value} {
return [expr {[string is list $value] && ([llength $value]&1) == 0}]
}
You can peek at the actual type in Tcl 8.6 with tcl::unsupported::representation but that's not advised because things like literals are converted to dictionaries on the fly. The following is legal, shows what you can do, and shows the limitations (
% set value {b c d e}
b c d e
% tcl::unsupported::representation $value
value is a pure string with a refcount of 4, object pointer at 0x1010072e0, string representation "b c d e"
% dict size $value
2
% tcl::unsupported::representation $value
value is a dict with a refcount of 4, object pointer at 0x1010072e0, internal representation 0x10180fd10:0x0, string representation "b c d e"
% dict set value f g;tcl::unsupported::representation $value
value is a dict with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x10101eb10:0x0, no string representation
% string length $value
11
% tcl::unsupported::representation $value
value is a string with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x100901890:0x0, string representation "b c d e f g"
% dict size $value;tcl::unsupported::representation $value
value is a dict with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x1008c7510:0x0, string representation "b c d e f g"
As you can see, types are a bit slippery in Tcl (by design) so you're strongly advised to not rely on them at all.
Your approach is flawed because Tcl has dynamic type system where the actual type of a value is able to morph dynamically and depends on the commands applied to it—observe:
$ tclsh
% info pa
8.5.11
% dict info {a b}
1 entries in table, 4 buckets
number of buckets with 0 entries: 3
number of buckets with 1 entries: 1
number of buckets with 2 entries: 0
number of buckets with 3 entries: 0
number of buckets with 4 entries: 0
number of buckets with 5 entries: 0
number of buckets with 6 entries: 0
number of buckets with 7 entries: 0
number of buckets with 8 entries: 0
number of buckets with 9 entries: 0
number of buckets with 10 or more entries: 0
average search distance for entry: 1.0
% llength {a b}
2
% string len {a b}
3
%
As you can see, the same value {a b} is a dictionary, a list and a string: in each case, the value acquires its "real" type in the very moment a Tcl command expecting a value of certain type converts the "default" type of the value, which is string, to the one the command operates on.
You should understand by now that trying to make a call dict? {a b} has little sence as the value {a b} is a perfect dict as well as a perfect list as well as a perfect string, and it could be, say, a perfect tuple if there are custom commands in the current interpreter working on tuples (lists of fixed length).
Hence the real approach you should take is to just blindly use dict command on those values passed to your commands you expect to contain dictionaries. If a user will manage to pass to your command something which is not interpretable as a dictionary, the dict command will fail, and that's a good thing to do as such an error is not really recoverable (it's a programming error).
Any attempt to count on a value's specific type is going again the grain of the very idea of the Tcl's implicit/dynamic typing. It's even true for the Tcl C API.
If you really meant to ask how to be sure the current Tcl version supports dict command, and not about the type of a particular value, test the Tcl's version somewhere at startup and save this as a flag, like this:
set hasDicts [expr {[package vcompare [info tclversion] 8.5] >= 0}]
But note that your code relying on the hasDicts value is now in some gray zone because if the user is not supplying you values you process with the dict command then what command you use to process them?
Please also note that the dict command can be added to a Tcl 8.4 interpreter in the form of the loadable module (see this).

Resources