PepeToro
PepeToro

Reputation: 559

Use string to select a function and/or a variable (Julia)

Suppose I have two functions:

function func_one(data, pars):
    ---
end

function func_two(data, pars):
    ---
end

Each function requires data and pars, but not necessarily of the same dimension, so I create

data_one = []
data_two = []
pars_one = []
pars_two = []

Next, I have a string variable, say name, that can be either "one" or "two" and would be used to select what type of triplet (func, data, pars) is going to be used later when I call everything. For example

name = "one"

and then I have

func = "func_" * name
data = "data_" * name
pars = "pars_" * name 

Then I would like to call such combination, for example

MainFunction(func,data,pars)

In reality I have many more than two possible triplets (func, data, pars). Of course at this moment this doesn't work because (func, data, pars) are strings, but I would like them to point to the corresponding function and variables. I want to do this so that a user can just change the string name, and then everything else is selected appropiately. How to do this (in Julia)?

Upvotes: 0

Views: 722

Answers (2)

Przemyslaw Szufel
Przemyslaw Szufel

Reputation: 42214

While Tasos is right that normally you should use functions, lambdas or data structure for that purpose I understand your question is actually about meta-programming. Here is how to do it:

Let us start by preparing functions and variables:

function main_fun(f,data,pars)
    println([f(),data,pars])
end

function f1()
    return "hello from f1"
end

data1 = "I'm data1"

pars1 = "I'm pars1"

Now, following your question, we assume that the name of actual parameters are hold in Strings - we need to convert them to Symbols:

f_name, data_name, pars_name = Symbol.(("f1","data1","pars1"))

Create the code (note the use of interpolation):

code = :(main_fun($f_name,$data_name,$pars_name))

Now let's get the things rolling (this is a sample console output):

julia> Main.eval(code)
["hello from f1", "that is data1", "that is pars1"]

Note that Main.eval needs to compile the code and it takes time.

Upvotes: 2

Tasos Papastylianou
Tasos Papastylianou

Reputation: 22215

You are thinking along the lines of evaluating strings, which is always a bad idea. Instead, focus on creating appropriate structures. If you really must use strings (even though thinking about this as arrays would be preferable), you can use said strings as keys in a dictionary, e.g.:

funcs = Dict{String, Function}();   #> Dict{String,Function} with 0 entries
funcs["one"] = (data, pars) -> print("Doing stuff with provided data and pars");
funcs["two"] = (data, pars) -> print("Doing something else with provided data and pars");

data = Dict{String, Any}();    #> Dict{String,Any} with 0 entries
data["one"] = [1 2 3 4 5];
data["two"] = [1;2;3;4;5];

pars = Dict{String, Any}();    #> Dict{String,Any} with 0 entries
pars["one"] = "Use turbo encabulator model";
pars["two"] = "Use encaboturbolation semantics";

# Use it
funcs["one"](data["one"], pars["one"])    #> prints "Doing stuff with provided data and pars"

As you can see from above, creating your functions as 'lambdas' makes it easy to assign them to a dictionary element. If you need multi-line functions, you can use a begin ... end block to achieve this.

Upvotes: 2

Related Questions