User Defined Functions Using Input

This is my first program in Julia. I am most familiar with python, but as a math teacher I fell in love with being able to define a function like you would on paper (e.g. f(n) = 4n+4).

I am trying to write a simple program that prints out values of n and f(n). I can get it to work exactly the way I would like, but only if I define the function within the code. However, I would like the user to be able to input the function. This way I could change the function on the fly during a class demonstration.

I saw there was a similar question to this a few months ago in a different forum. People suggested using Meta.parse(). I read the docs and tried using it in my program but am now stuck. It works great to set the upper bound of the domain, but not to create the function. If anyone has any suggestions I would love some help.

    #!julia
    println("Enter upper bound: ")
    max = Meta.parse(readline()) 
    
    println("Enter your function: ")
    func = Meta.parse(readline())
    f(n) = func
    
    #print top of table
    println("-"^(length(string(max)) + length("$(f(max))") + 12))
    
    #print each row with n -> f(n)
    for n in 0: max
        print("|  ")
        print(lpad(n, length(string(max)), " "), "  ->  ", 
              lpad((f(n)), length("$(f(max))"), " "))
        println("  |")
    end
    
    #print bottom of table
    println("-"^(length(string(max)) + length("$(f(max))") + 12))

Current output:

    Enter upper bound:
    10
    Enter your function:
    4n+4
    --------------------
    |   0  ->  4n + 4  |
    |   1  ->  4n + 4  |
    |   2  ->  4n + 4  |
    |   3  ->  4n + 4  |
    |   4  ->  4n + 4  |
    |   5  ->  4n + 4  |
    |   6  ->  4n + 4  |
    |   7  ->  4n + 4  |
    |   8  ->  4n + 4  |
    |   9  ->  4n + 4  |
    |  10  ->  4n + 4  |
    --------------------

Desired output (minus the ability to input function) with f(n) = 4n+4:

    Enter upper bound:
    10
    Enter your function:
    ----------------
    |   0  ->   4  |
    |   1  ->   8  |
    |   2  ->  12  |
    |   3  ->  16  |
    |   4  ->  20  |
    |   5  ->  24  |
    |   6  ->  28  |
    |   7  ->  32  |
    |   8  ->  36  |
    |   9  ->  40  |
    |  10  ->  44  |
    ----------------

If you just want to allow an integer here, I would tend to do something more restrictive like parse(Int, readline()), rather than parsing arbitrary Julia expressions.

Maybe you want something like:

f = eval(:(n -> $(Meta.parse(readline()))))
4 Likes

Yes! You are my hero. Thank you.

So if I am understanding, your first suggestion restricts the first input to integers only by only parsing over Int.

I don’t fully understand the syntax of the second suggestion, but it did work. Why is it necessary to evaluate there when I am not actually evaluating the function until the for loop later?

Meta.parse returns an Expr, which is why your original example keeps returning the expression 4n + 4 no matter the input. :(n -> $(Meta.parse(readline()))) simply inserts the user-input expression into yet another expression for anonymous function with argument n. By evaluating this expression, you are able to assign the actual function to f.

1 Like

Thank you! I think I need to play around some more, but this is helpful!

You’re welcome! Do check out the documentation on interpolating and evaluating expressions. Julia’s metaprogramming stuff is a rabbit hole, but you’d get the hang of it over time!

1 Like