Can I convert a 'piece of code' to an expression object?

metaprogramming

#1

Well, the question is as simple as that. I’m almost done reading the metaprogramming section, on the manual. I’m completely new to the concept, and quite new to Julia too (although I’ve written some programs already and I’m used to python, whose syntax resembles Julia’s - albeit the programming style not quite so). As it seems to me, if I want my program to change pieces of code while running, I should define these pieces as expressions – for instance, defining a variable x = :(for i in 1:10 println(i) end) – and use eval() on them when needed, but I can’t do it the other way around, i.e., defining

x = for i in 1:10 println(i) end

and then using something over x yielding the expression

:(for i in 1:10 println(i) end).

Is that correct?


#2

Not really. For most metaprograming you’ll use macros which is not eval.

Correct. Though it is not what the title suggest. x is not “a piece of code”. x is the result of an expression. There are ways, through reflection, to get “a piece of code” and it’s in principle possible to convert that to “an expression”. However, the result doesn’t carry any information about what it’s evaluated from so converting that to an expression is impossible.


#3
julia> parse("for i in 1:10 println(i) end") 
:(for i = 1:10 # none, line 1:               
        println(i)                           
    end)                                     
                                             
julia> eval(ans)                             
1                                            
2                                            
3                                            
4                                            
5                                            
6                                            
7                                            
8                                            
9                                            
10                                           

#4

Correct, yes, usually macros are used. eval() is, though, the minimal operation over an expression that yields its value - that’s what I tried to mean: instead of defining a block of code, like a for loop, to define an expression that evals to this block of code.

Indeed, I should have used some quote marks over the ‘piece of code’. The problem is exactly that, and clarifying the fact that in the second case x is the result of the evaluation (despite that being quite obvious and I didn’t notice properly) of the code-block, not the code-block, answers the question.

In any case, could you tell me more about how, and in what kind of situations it is possible, to get a piece of code?


#5

While possible, It is not clear why you would want to do that. Treating code as mutable does not mesh well with Julia’s performance model, you will be penalized on compile time. Also, it is very error prone.

Perhaps if you explained what you are doing, you would get a solution to your problem.


#6

Well, I don’t have exactly a concrete objective by doing so. For now, I’m just trying to explore the metaprogramming support Julia offers and the very concept of metaprogramming itself inasmuch learn how to use it. But, in the future, I wish to delve into concepts such as self-modifying codes, Gödel machines etc. Also (but that I don’t believe is as close to the topic), I’d wish to try to write a first-order logic theorem prover - and for that I think working with expressions in syntactic level is paramount.


#7

Honestly, I don’t think Julia is the best language for that. The AST is somewhat complicated, not nearly as simple as S-expressions in Lisps, and as I said, there will be a performance penalty. I would imagine you would be much better off with a Lisp/Scheme.

Yes, but for the reasons above, you probably want to avoid working with Julia’s representation of expressions, and create your own types, which you can dispatch on, etc.


#8

That’s good to know. I’m indeed planning to learn Scheme in the near future. In any case, now I’m working with some other things (machine learning) and that’s the main reason why I’m using Julia. I could say I’m trying to learn the language as deeply as I can, and learning about metaprogramming, particularly within Julia, is, say, a parallel goal. The more long-term oriented goals (related to metaprogramming) might be pursued on more adequate languages. I wish I could, nonetheless, explore at least a little what are the possibilities and limitations of Julia’s metaprogramming support.
Let me say two things I was trying to write and failed (I might paste the codes if requested, but I think maybe that would be more suitable on another topic, being this one just for you to give me some direction over whether it is or not suitable to do such things in Julia), that might not be most efficiently treated this way but that’s what came to me as some exercise:

  1. feeding a function a while loop of the form while expr ... end, with the function refreshing expr whenever it is met;
  2. a function that generates nested expressions, like taking (a + b) and 1 as input and yielding (a + (a + b)) as output.

#9

It is Turing complete, so strictly speaking there are no limitations. It is just that

  1. some things are not convenient,
  2. the result will need to be compiled.

Otherwise, Julia macros are very similar to those of the Lisp family, mutatis mutandis. Their idiomatic use is for source code transformation at the time the code is read.


#10

Sure possible, I think this is what you are talking about?

julia> function nest(f::Function,x,n)
           out = x
           for k ∈ 1:n
               out = f(out)
           end
           return out
       end
nest (generic function with 1 method)

julia> f(x) = :(a+$x)
f (generic function with 1 method)

julia> nest(f,:b,3)
:(a + (a + (a + b)))


#11

To answer your question specifically, yes it is possible:

julia> function givewhile(ex)
           return quote
               c = 0
               while $ex
                   c += 1
                   println("doing some stuff")
               end
           end
       end

givewhile (generic function with 1 method)

julia> for expr ∈ [:(c < $n) for n ∈ 3:-1:1]
           eval(givewhile(expr))
           println("done")
       end
doing some stuff
doing some stuff
doing some stuff
done
doing some stuff
doing some stuff
done
doing some stuff
done

#12

Sorry the delayed reply. Many thanks, that is precisely what I was trying to do. And, boy, I think I wasn’t going to reach that anywhere soon.