# Auto-evaluate function/expression in local scope

**URL:** https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515
**Category:** General Usage
**Created:** [October 10, 2022, 9:31am UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515 "2022-10-10T09:31:19Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![capri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/capri/32/39015_2.png) [@capri](https://discourse.julialang.org/u/capri)
#### Post date: [October 10, 2022, 9:31am UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/1 "2022-10-10T09:31:19Z")

</div>

Hi guys,

I have a problem which I think should be fairly easy to solve (I guess) but I don’t know how.  
I’ll try to describe it as on-point as possible.

I want to define an array of “formulas” that I want to evaluate at different times.  
I tried it with expressions and it worked really well at first sight. Here is a simplified example:

```julia
ex1 = :(3 + a^2)
ex2 = :(5 + a)
ex3 = :(12)
arr = [ex1, ex2, ex3]

a=15
eval.(arr)

```

This is exactly what I need (I love that I can evaluate the whole array with just one `.eval` call and get an array back) BUT: it only works with global `a` since expressions always get evaluated in global scope.  
Now where I want to evaluate this stuff is in a scope where `a` is local.

Of course I googled and found the advice “try it with functions”. Apart from the problem that I don’t know how to call a bunch of functions in an array with one call I also wasn’t successful in trying to access local variables.

This simple example (with just one function) doesn’t work:

```julia
f = () -> a + b^2 + 20

for a = 1:10
    b = a-1
    println(f())
end

```

I get an `UndefVarError: b not defined`.

How could I make this work?  
Any help is greatly appreciated!

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [October 10, 2022, 10:00am UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/2 "2022-10-10T10:00:20Z")

</div>

My spider senses give me the suspicion of a [XY problem - Wikipedia](https://en.wikipedia.org/wiki/XY_problem) but welcome to this fine community, I am sure you are not a villain 😉

What I mean is, that just solving your direct questions seem to lead you on a bad path, where other problems will likely arose.

For your first question, what do you mean by local. If local is local to a module there is

```julia
Base.eval(m::Module, x)

```

but this is not a recommendation to use it.

For your second question it would be best to just use function parameters, like e.g.:

```julia
julia> f = [(a,b) -> a + b^2 + 20 , (a,b) -> a + b^2 + 10]
2-element Vector{Function}:
 #25 (generic function with 1 method)
 #26 (generic function with 1 method)

julia> for a = 1:10
           b = a-1
           println( [x(a,b) for x in f] )
       end
[21, 11]
[23, 13]
[27, 17]
[33, 23]
[41, 31]
[51, 41]
[63, 53]
[77, 67]
[93, 83]
[111, 101]

```

But for better advice we need more information about your real problem you like to solve.

---

<div class="post-metadata">

### Author: ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)
#### Post date: [October 10, 2022, 10:21am UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/3 "2022-10-10T10:21:17Z")

</div>

Instead of local variables, you could use a dictionary with symbols as keys that work as variable names. Then, you could make a macro that transforms formulas into functions that take such dictionaries:

```julia
using MacroTools

macro makefun(expr)
    new_expr = MacroTools.postwalk(expr) do subex
        if @capture(subex, :s_)
            return :(dic[$(QuoteNode(s))])
        else
            return subex
        end
    end
    return :( dic -> $new_expr )
end

f = @makefun :a + :b^2 + 20

variables = Dict()
for a = 1:10
	variables[:a] = a
	variables[:b] = a - 1
	println(f(variables))
end

```

Note: inspired in:

> [@Create Formulas with Macros](https://discourse.julialang.org/t/create-formulas-with-macros/87951):
>
> Hi all, I’m practicing working with macros and ran into an idea that I want to attempt to implement. Essentially, I want to create a macro @form that takes a formula expression. The expression would then be applied to a named tuple and return a new named tuple based on the formula values. Without a macro, I can achieve this with the following: # create named tuple nt = (; a =1, b=2) # function of interest formulafun(nt) =(:a, nt[:a] + nt[:b] +1) function foo(nt, formulafun) operation…

---

<div class="post-metadata">

### Author: ![capri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/capri/32/39015_2.png) [@capri](https://discourse.julialang.org/u/capri)
#### Post date: [October 10, 2022, 10:36am UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/4 "2022-10-10T10:36:29Z")

</div>

Thank you both so much!

@oheil to answer your first question: I mean local as in the local scope of another function where `a` and `b` would be parameters of said function. Your answer to my second question is a nice solution though - evaluating the functions in a list comprehension is actually a working idea.

Beyond that I was just wondering if I could also find a solution to address future local variables that I already know the names of. This is (to some length) what @heliosdrm provided.

Of course I could provide more information of the real problem but I don’t think it’s needed here. This was more of a “what would be an elegant way to achieve this” question and I got some nice ideas that I can take to my co-researchers to discuss.

Thanks again

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [October 10, 2022, 11:01am UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/5 "2022-10-10T11:01:08Z")

</div>

There is also

> **[GitHub - JuliaStaging/GeneralizedGenerated.jl: A generalized version of Julia...](https://github.com/JuliaStaging/GeneralizedGenerated.jl)**
>
> A generalized version of Julia generated functions @generated to allow closures in generated functions and avoid the use of runtime eval or invokelatest. - GitHub - JuliaStaging/GeneralizedGenerate...

which maybe of use for you.

---

<div class="post-metadata">

### Author: ![Eben60](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eben60/32/13475_2.png) [@Eben60](https://discourse.julialang.org/u/Eben60)
#### Post date: [October 10, 2022, 12:26pm UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/6 "2022-10-10T12:26:34Z")

</div>

> [@capri](#):
>
> I don’t know how to call a bunch of functions in an array with one call

E.g.

```julia
fn1(a) = 3 + a^2
fn2(a)= 5 + a
fn3(a) = 12
arr = [fn1, fn2, fn3]

a=15
x = [f(a) for f in arr]

julia> x
3-element Vector{Int64}:
 228
  20
  12

```

Edit: alternatively using map

```julia
y = map(x -> x(a), arr)

```

As an advice (from my own experience, too) - don’t start with metaprogramming before you are fluent with the language. And then you’d in most cases find out, you don’t need it anyway.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 10, 2022, 12:33pm UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/7 "2022-10-10T12:33:03Z")

</div>

> [@capri](#):
>
> I mean local as in the local scope of another function where `a` and `b` would be parameters of said function

Julia does not have `eval` in local scope, by design. This is in part a reason why julia can be fast & dynamic at the same time, with lots of compilation to native code.

---

<div class="post-metadata">

### Author: ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)
#### Post date: [October 10, 2022, 3:18pm UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/8 "2022-10-10T15:18:30Z")

</div>

> [@capri](#):
>
> I don’t know how to call a bunch of functions in an array with one call

You can use the pipe operator:

```julia
a .|> f

```

where `f` is your array of functions.

---

<div class="post-metadata">

### Author: ![Eben60](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eben60/32/13475_2.png) [@Eben60](https://discourse.julialang.org/u/Eben60)
#### Post date: [October 10, 2022, 6:38pm UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/9 "2022-10-10T18:38:55Z")

</div>

or

```julia
ff(fn, x) = fn(x)
ff.(arr, a)

```

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [October 10, 2022, 8:07pm UTC](https://discourse.julialang.org/t/auto-evaluate-function-expression-in-local-scope/88515/10 "2022-10-10T20:07:46Z")

</div>

> [@capri](#):
>
> This simple example (with just one function) doesn’t work:
> 
> ```julia
> f = () -> a + b^2 + 20
> 
> for a = 1:10
> b = a-1
> println(f())
> end
> 
> ```
> 
> I get an `UndefVarError: b not defined`.
> 
> How could I make this work?  
> Any help is greatly appreciated!

Julia (as almost languages nowadays) is lexically scoped, i.e., variables get the values from the lexical context, i.e., the local block in the source code, around the definition of an expression:

```julia
f = () -> a + b^2 + 20 # f is defined in the global scope, ergo, a and b refer to names in the global scope

```

Thus, calling `f()` fails in any context as no global bindings for `a` and `b` are available.

```julia
g = let a = 10
          b = 2
          () -> a + b^2 + 20 # defined in the context with a=10 and b=2
    end

```

Here, the function `g` closes over the values from the lexical context around its definition – therefore it’s commonly called a _closure_. Now, no matter in which context it is called `g()` will evaluate to 34. Even if you define different bindings for `a` and `b` in the global scope:

```julia
julia> a = 3; b = 5
5

julia> g()
34

```

What you would need to make the example work is _dynamic scope_. In this case, variables are looked up in the current runtime environment. This can be emulated in Julia using `task_local_storage`:

```julia
ff = () -> task_local_storage(:a)^3 + 1

task_local_storage(ff, :a, 4) # Call ff in an environment with a=4, i.e., let a = 4 ff() end if Julia were dynamically scoped

```

In most cases it is better and easier to pass variables as arguments. If more flexibility is needed, passing a dictionary as suggested by @heliosdrm is a good option – in the end, `task_local_storage` is like a global dictionary that can be accessed from, i.e., is implicitly passed to, any function.
