Hello,

I want to push a number of anonymous functions to an array. Each function is largely the same but in some cases some addends are scalars instead of variables. Say that there are three different cases, like:

case 1) f(x) = x[1]+x[3]+cos(x[1]-x[2])

case 2) f(x) = x[1]+x[3]+cos(a) where a is a scalar

case 3) f(x) = x[1]+x[3]+cos(x[1]-x[3])

(in reality the function is way bigger).

So, instead of writing something like this:

```
function_array = []
for case in cases
if case.type == 1
push!(functions_array, x->x[1]+x[3]+cos(x[1]-x[2]) )
elseif case.type ==2
etc.
```

I figure I’d use metaprogramming and do

```
function_array = []
for case in cases
if case.type == 1
cos_arg = :(x[1]-x[2])
elseif case.type == 2
cos_arg = :(a)
else
cos_arg = :(x[1]-x[3])
end
push!(function_array, x->x[1]+x[3]+cos(eval(Meta.parse(cos_arg))) )
end
```

But then I realized that `eval(Meta.parse(...))`

is in general a bad idea and `eval`

only does it in the global scope, which is not good in my case.

So I guess I should write a macro instead, but it’s something I never did and I am not sure on how to best approach this. I did read the metaprogramming section of the manual but I am still a bit confused, and could use some tips.

Hmm, maybe MWE is incomplete, but it looks like you do not need metaprogramming. Functions are first-class citizens in Julia, so you can use them as lego blocks to build arbitrarily complicated expressions.

```
function_array = []
cases = [(; type = 1), (; type = 2), (; type = 3)]
a = 1
for case in cases
f1 = if case.type == 1
x -> x[1] - x[2]
elseif case.type == 2
x -> a
else
x -> x[1] + x[3]
end
push!(function_array, x -> x[1] + x[3] + cos(f1(x)))
end
```

and sanity check

```
julia> map(i -> function_array[i]([1, 4, 7]), 1:3)
3-element Vector{Float64}:
7.010007503399555
8.54030230586814
7.854499966191386
```

1 Like

Thanks, that’s quite interesting and I did not know that!

However, I am afraid that I have over-simplified my problem, so in my actual case this solution does not seem to work. Let me see if I can explain my problem a bit more in detail. I am trying to write a function more like the following (again with the eval(Meta.parse(…)) approach):

```
function func_name(connected_branches::Array, case, function_array::Array, angle_from, angle_to)
ev_arg = eval ∘ Meta.parse ∘ string
if case == 1
cos_arg = :(deg2rad.([0, 120, -120])[c] - x[angle_to[br][d]]) # angle_from and angle_to are arrays of scalars
else
cos_arg = :(x[angle_from[c]] - x[angle_to[br][d]])
end
for c in 1:3
push!(function_array, x->sum( (x[1]+x[2]+cos(ev_arg(cos_arg)) for d in 1:3 if d!=c) for br in connected_branches) )
end
end
```

so, basically, if I try to apply the method you suggested directly, I get `UndefVarError: br not defined`

, because this is somehow “nested” in the variable index.

The inputs would look sort of like:

```
connected_branches = [1, 2]
case = 1
function_array = []
angle_from = [1, 2, 3]
angle_to = [[2, 4, 6], [1, 3, 5]]
```

I hope it is kind of clear and makes somewhat sense. Basically, `angle_to`

and `angle_from`

host the indexes of the variable array that I want to choose.

You can make `c`

, `d`

and `br`

arguments of internal functions

```
function func_name(connected_branches::Array, case, function_array::Array, angle_from, angle_to)
f1 = if case == 1
(x, c, d, br) -> deg2rad.([0, 120, -120])[c] - x[angle_to[br][d]] # angle_from and angle_to are arrays of scalars
else
(x, c, d, br) -> x[angle_from[c]] - x[angle_to[br][d]]
end
for c in 1:3
push!(function_array, x->sum( (x[1]+x[2]+cos(f1(x, c, d, br)) for d in 1:3 if d!=c) for br in connected_branches) )
end
end
```

1 Like

works perfectly, thank you!

1 Like