How do I create an anonymous function from external variables?

I am trying create a anomymous function with external variables

idx = 3; #External Variable
f = x -> x[idx];

As an example

idx = 2 #change the value
x = [2,3,5]
f(x)
3

I would expect the output to be like

f = x -> x[3]
f(x)
5

Any suggestions for decoupling the external variable?

f = x -> x[eval(:idx)];

@jling Thank you so much for your help.

I get this error

idx = nothing
f(x)
ArgumentError: `nothing` should not be printed; use `show`, `repr`, or custom output instead.

what behavior do you expect to get, this is basically:

julia> x = [2,3,5]
3-element Array{Int64,1}:
 2
 3
 5

julia> x[nothing]

No that’s not going to make any difference.

It’s not super clear what you want. Your function is referencing two “external variables” (global variables) x and idx. Are you just saying that you want to make one of them refering to the global variable x while the other one doesn’t refer to the global variable idx anymore?

(edit: sorry, I somehow thought x is a global variable and not the argument, anyway, apart from the mentioning of x above, everything else are still correct so I’ll just leave it as is…)

In that case, the solution should come out on it’s own. You just need to make idx not be the global variable anymore, i.e. you need to make it a local variable. The way to introduce a local scope is let so you basically need

f = let idx=idx
   x -> x[idx]
end

Of course if you don’t need idx to be a variable, you can splice that into the code directly, like @eval x->x[$idx] but that’s really an overkill.

1 Like

what do you mean?

julia> f = x -> x[eval(:idx)];

julia> idx = 2
2

julia> x = [2,3,5]
3-element Array{Int64,1}:
 2
 3
 5

julia> f(x)
3

julia> idx = 3
3

julia> f(x)
5

and his function is NOT referring to 2 global variable because that’s an anonymous function

I believe you are showing the exact result that was not expected.
What I mean is that your function behaves identically with the original one.

julia> f = x -> x[idx]
#3 (generic function with 1 method)

julia> idx = 2
2

julia> x = [2,3,5]
3-element Array{Int64,1}:
 2
 3
 5

julia> f(x)
3

julia> idx = 3
3

julia> f(x)
5

Yeah, see my edit above. However, it has nothing to do with the fact that it’s an anonymous function. It’s exactly the same for f(x) = x[idx], which is not anonymous. I just missed the x-> part, i.e. that x is the argument, which IS the reason why it’s only refering to 1 global variable and not 2.

ah, my mistake, I thought he was trying to get that result. Sorry for the confusion.

If the question was to get that result for a function constructed in a local scope, then yes, what you had is a valid answer. It’s not a good answer though and should be discouraged like any unnecessary use of eval. The correct solution is to make sure you resolve your variable to the global one explicitly, i.e. by qualifying with the module it’s in, i.e. x->x[<M>.idx]. In this case, the <M> is the current module, i.e. @__MODULE__ so it should be x->x[(@__MODULE__).idx] (too lazy to check if the () is required…edit: actually I’m pretty sure it is… anyway…)

edit2: of course using global also work. It’s just dirtier for one-liner, but you can do x->(global idx; x[idx])…

2 Likes