If I have 2 variables, a=[.3, .2, .4]; b=[.1, .2, .3]; I can create a string with the name of the variable using a macro:
macro varname(arg)
string(arg)
end
#varname(a)
now say I have a function and I want to pass it an arbitrary number of arguments and use the actual variable names that are being given to function to create dictionary keys:
function test(arguments...)
Dict(Symbol(#varname(i)) => i for i in arguments)
end
this won't work because #varname will take i and create "i", so for example:
out=test(a,b)
the output I would like is:
Dict("a" => [.3, .2, .4], "b" => [.1, .2, .3])
Is there a way to achieve this behavior?
Parameters.jl has such a macro. It works like this:
using Parameters
d = Dict{Symbol,Any}(:a=>5.0,:b=>2,:c=>"Hi!")
#unpack a, c = d
a == 5.0 #true
c == "Hi!" #true
d = Dict{Symbol,Any}()
#pack d = a, c
d # Dict{Symbol,Any}(:a=>5.0,:c=>"Hi!")
If you want to know how it's done, just check its source:
https://github.com/mauro3/Parameters.jl/blob/v0.7.3/src/Parameters.jl#L594
Related
I have the following macro and it should allow me to build a struct with one or 2 arguments only!
macro baseStruct(name, arg)
if length(arg.args)==2 && isa(arg.args[1],Symbol) || length(arg.args)==1
aakws = Pair{Symbol,Any}[]
defaultValues=Array{Any}(nothing,1)
field_define(aakws,defaultValues,1,arg,first=true)
:(struct $name
$(arg.args[1])
function $name(;$(arg.args[1])=$(defaultValues[1]))
new(check($name,$(arg.args[1]);$aakws...))
end
end)
else length(arg.args)==2 && !isa(arg.args[1],Symbol)
aakws1 = Pair{Symbol,Any}[]
aakws2 = Pair{Symbol,Any}[]
defaultValues=Array{Any}(nothing,2)
field_define(aakws1,defaultValues,1,arg)
field_define(aakws2,defaultValues,2,arg)
:(struct $name
$(arg.args[1].args[1])
$(arg.args[2].args[1])
function $name(;$(arg.args[1].args[1])=$(defaultValues[1]),$(arg.args[2].args[1])=$(defaultValues[2]))
new(check($name,$(arg.args[1].args[1]);$aakws1...),check($name,$(arg.args[2].args[1]);$aakws2...))
end
end)
#baseStruct test(
(arg1,(max=100.0,description="this arg1",min=5.5)),
(arg2,(max=100,default=90))
)
The macro will expand to:
struct test
arg1
arg2
end
and the following instance:
test1=test(arg1=80.5)
should give:
test1(arg1=80.5,arg2=90)
#check_function returns the argument. It allows me to check the argument in a specific way.
check(str,arg;type=DataType,max=nothing,min=nothing,default=nothing,description="")
#do somthing
return arg
end
#field_define_function it takes the second parameter from the macro as Expr. and convert it to a array with Pair{Symbol, Any} and then assign it to aakws.
I can extend this Code for more arguments, but as you can see it will be so long and complex. Have anybody a tip or other approach to implement this code for more/unultimate arguments in a more efficient way?
I don't have the code for field_define or check, so I can't work your example directly. Instead I'll work with a simpler macro that demonstrates how you can splat-interpolate a sequence of Expr into a quoted Expr:
# series of Expr like :(a::Int=1)
macro kwstruct(name, arg_type_defaults...)
# :(a::Int)
arg_types = [x.args[1]
for x in arg_type_defaults]
# :a
args = [y.args[1]
for y in arg_types]
# build :kw Expr because isolated :(a=1) is parsed as assignment
arg_defaults = [Expr(:kw, x.args[1].args[1], x.args[2])
for x in arg_type_defaults]
# splatting interpolation into a quoted Expr
:(struct $name
$(arg_types...)
function $name(;$(arg_defaults...))
new($(args...))
end
end
)
end
This macro expands #kwstruct D a::Int=1 b::String="12" to:
struct D
a::Int
b::String
function D(; a = 1, b = "12")
new(a, b)
end
end
And you can put as many arguments as you want, like #kwstruct(F, a::Int=1, b::String="12", c::Float64=1.2).
P.S. Splatting interpolation $(iterable...) only works in quoted Expr, which look like :(___) or quote ___ end. If you're constructing with an Expr() call, just use splatting:
vars = (:b, :c)
exq = :( f(a, $(vars...), d) ) # :(f(a, b, c, d))
ex = Expr(:call, :f, :a, vars..., :d) # :(f(a, b, c, d))
exq == ex # true
I have a function which is very open-ended that I use in several different applications. Instead of changing it everytime, I would like to pass several command lines as input for the function to evaluate using something like the eval function.
Thus, for example, my argument would be:
str={'a=32;
b=a+3*a^2+pi;
c=sin(a)+cos(b)^2;'}
then I could call the function with str as an argument:
x=func(str)
these lines would be evaluated inside the function
how?
Thanks alot!
I think #Daniel is right that function handles are the way forward. Based on your example, this is how you'd do it:
function x = testfun( a, bfun, cfun )
b = bfun(a);
c = cfun(a, b);
x = a + b + c;
end
Then you'd call it like this:
x = testfun( 32, #(a)(a+3*a^2+pi), #(a,b)(sin(a)+cos(b)^2) );
I have a structure, from which I want to access repeatedly the fields to I load them in the current space like this (where M is type with fields X and Y):
X = M.X
Y = M.Y
in R, I often use the with command to do that. For now I would just like to be able to have a macro that expends that code, something along the lines of
#attach(M,[:X,:Y])
I am just not sure how exactly to do this.
I've included in this answer a macro that does pretty much what you describe. Comments explaining what's going on are inline.
macro attach(struct, fields...)
# we want to build up a block of expressions.
block = Expr(:block)
for f in fields
# each expression in the block consists of
# the fieldname = struct.fieldname
e = :($f = $struct.$f)
# add this new expression to our block
push!(block.args, e)
end
# now escape the evaled block so that the
# new variable declarations get declared in the surrounding scope.
return esc(:($block))
end
You use it like this: #attach M, X, Y
you can see the generated code like so: macroexpand(:(#attach M, X, Y)) which will show something like this:
quote
X = M.X
Y = M.Y
end
I am trying to allow a function to have access to the base workspace using the evalin function, but I am having trouble. Here is a simple example:
My main code:
A = 1;
B = 2
evalin('base','[ C ] = FUN(B)');
C
My Function:
function [C ] = FUN( B )
C = A + B;
end
My error:
Undefined function or variable 'A'.
Error in FUN (line 4)
C = A + B;
Error in Test (line 4)
evalin('base','[ C ] = FUN(B)');
So, the function is not being evaluated in the base workspace because it does not know what the value of A is.
Can anyone suggest something? I have a lot of variables that I need to access in several functions and I don't want to pass them and I don't want to use global variables.
Thanks!
From the evalin documentation,
evalin(ws, expression) executes expression, a string containing any valid MATLABĀ® expression, in the context of the workspace ws. ws can have a value of 'base' or 'caller' to denote the MATLAB base workspace or the workspace of the caller function.
So the line of code
evalin('base','[ C ] = FUN(B)');
evaluates only the line of code
[ C ] = FUN(B)
in the context of the base workspace. It does not evaluate the body of the function within the context of the base workspace. So the error that you are observing makes sense.
Is there a particular reason why you don't want to pass the variables in to the function? Why do you have several variables in the base (?) workspace, or do you just have several variables within a main function?
If the latter, you could use nested functions to have access to the variables declared in the caller (function) workspace. For example, suppose you have a main function like
function main()
A = 1;
B = 2;
C = FUN();
function [C] = FUN()
C = A + B;
end
end
The function FUN has access to both A and B and so you don't have to pass in any arguments.
An alternative to passing in several different inputs, is to just pass in a structure that has different fields that your function can access at will. Using the above example, we could do the following
function main()
A = 1;
B = 2;
data.A = A;
data.B = B;
C = FUN(data);
end
function [C] = FUN(data)
C = data.A + data.B;
end
In this case, the function FUN can be a function within its own file or declared after main. Again, we only pass in one argument that has all the data that the function needed.
Actually Evalin function is used to take data from base workspace:
Syntax is :
evalin('base','variable')
Evalin function is used in the function .
For example see the below function
function [out1 out2 out3]=main_fun(in1,in2)
out1=in1+in2;
out2=in1-in2;
in3=evalin('base','in3');
in4=evalin('base','in4');
out3=in3+in4;
end
Here out3 value will have the sum of in3 and in4 from workspace.
out1 and out2 will have the sum and difference of in1 and in2 from current function workspace.
I'm trying to understand the conceptual difference between call by reference, value, and name.
So I have the following pseudocode:
foo(a, b, c)
{
b =b++;
a = a++;
c = a + b*10
}
X=1;
Y=2;
Z=3;
foo(X, Y+2, Z);
What's X, Y, and Z after the foo call if a, b, and c are all call by reference?
if a, b, and c are call-by-value/result?
if a, b, and c are call-by-name?
Another scenario:
X=1;
Y=2;
Z=3;
foo(X, Y+2, X);
I'm trying to get a head start on studying for an upcoming final and this seemed like a good review problem to go over. Pass-by-name is definitely the most foreign to me.
When you pass a parameter by value, it just copies the value within the function parameter and whatever is done with that variable within the function doesn't reflect the original variable e.g.
foo(a, b, c)
{
b =b++;
a = a++;
c = a + b*10
}
X=1;
Y=2;
Z=3;
foo(X, Y+2, Z);
//printing will print the unchanged values because variables were sent by value so any //changes made to the variables in foo doesn't affect the original.
print X; //prints 1
print Y; //prints 2
print Z; //prints 3
but when we send the parameters by reference, it copies the address of the variable which means whatever we do with the variables within the function, is actually done at the original memory location e.g.
foo(a, b, c)
{
b =b++;
a = a++;
c = a + b*10
}
X=1;
Y=2;
Z=3;
foo(X, Y+2, Z);
print X; //prints 2
print Y; //prints 5
print Z; //prints 52
for the pass by name;
Pass-by-name
Call by Value : normal way... values of actual parameters are copied to formal parameters.
Call by Reference : instead of the parameters, their addresses are passed and formal parameters are pointing to the actual parameters.
Call by Name : like macros, the whole function definition replaces the function call and formal parameters are just another name for the actual parameters.
By value - there is no changes out the function. all your actions vanish when the function finished.
By reference - your actions indeed changes the variables.
By name - I've never heard ...
Passing x+1 is not change, just tells to the function 3 instead 2 or etc...
This won't change the value of X, Y or Z if it is pass-by-value. When you use a function such as "foo()", it basically copies the variables (x, y and z) into other variables (a, b, and c) and does certain actions with them, without changing the originals (x, y and z). For you to change a value you would have to return a value, something like this:
foo(a, b, c)
{
a = a++;
b = b++;
c = a + b * 10;
return c;
}
x = 1;
y = 2;
z = 3;
z = foo(x, y+2)
Then x and y would be the same, but z would be (x+1)+(y+1)*10 which in this case would be 32.
in javascript :
primitive type variable like string,number are always pass as pass
by value.
Array and Object is passed as pass by reference or pass by value based on these condition.
if you are changing value of that Object or array with new Object or Array then it is pass by Value.
object1 = {item: "car"};
array1=[1,2,3];
here you are assigning new object or array.you are not changing the value of property
of old object.so it is pass by value.
if you are changing a property value of an object or array then it is pass by Reference.
object1.item= "car";
array1[0]=9;
here you are changing a property value of old object.you are not assigning new object or array to old one.so it is pass by reference.
Code
function passVar(object1, object2, number1) {
object1.key1= "laptop";
object2 = {
key2: "computer"
};
number1 = number1 + 1;
}
var object1 = {
key1: "car"
};
var object2 = {
key2: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1.key1);
console.log(object2.key2);
console.log(number1);
Output: -
laptop
bike
10
In Call by value, a copy of the variable is passed whereas in Call by reference, a variable itself is passed. In Call by value, actual and formal arguments will be created in different memory locations whereas in Call by reference, actual and formal arguments will be created in the same memory location.