Converts the given string into code with metaprogramming

When I get a string s=“x^2+1” (It can only be a string), then how do I create a function f(x)=x^2+1. I tried the following with metaprogramming, but it didn’t work

julia> s="x^2+1"
"x^2+1"

julia> f(x)=eval(Meta.parse(s))
f (generic function with 1 method)

julia> f(1)
ERROR: UndefVarError: x not defined
Stacktrace:
 [1] top-level scope
   @ none:1
 [2] eval
   @ ./boot.jl:373 [inlined]
 [3] eval
   @ ./client.jl:453 [inlined]
 [4] f(x::Int64)
   @ Main ./REPL[2]:1
 [5] top-level scope
   @ REPL[3]:1

It seems that eval() can only work on expressions that contain global variables that have been defined.

How about this:

julia> s="x^2+1"
"x^2+1"

julia> eval(Meta.parse("f(x)="*s))
f (generic function with 1 method)

julia> f(1)
2

Of course. What you do is the same as entering at the REPL:

x^2+1

which gives you the same error if x is not defined.
The argument eval is evaluated independently from what you put in front of it, (f(x) in this case).
What you actually do, is defining a function which ignores its argument x. The body of the function does the eval in the Main scope, and not in the scope of the function, so it’s a different x as the functions argument.

help?> eval
...
  eval(expr)

  Evaluate an expression in the global scope ...
1 Like

Well, this works in the REPL.

You’re right! This cannot be defined in the function body.

Edited my typo… edited typo2 … and back… huuh, I am confused today…

Apart from “please try to avoid doing this in the first place” this is hard to answer properly without knowing how it’s going to be used and how the example is supposed to generalize.

Here is another approach that may or may not be useful:

julia> function foo(s, x)
           f = eval(Meta.parse("x -> $s"))
           return Base.invokelatest(f, x)
       end
foo (generic function with 1 method)

julia> foo("2x+1", 3)
7

Cf. Passing a string into function as a expression - #14 by GunnarFarneback

4 Likes

It was very helpful to me, thank you so much!