Thanks! That’s helpful.
FWIW, this (I think it’s a grad school course project at MIT) implemented GP in Julia by operating on the AST’s. And, this talk from ClojureConj 2015 gives the same explanation for GP in Lisp as Simon does (and also around 13:30 he explicitly works on subtrees).
I think AST is important for re-combinations and mutations, not for the generation of the initial programs. That is, for programs to evolve, they need to produce children that are like the parents, but with “lines of code” (or something comparable) swapped. (Also, the functions not only need to be generated and evaluated, they need to be stored somewhere so they can be used to produce child functions. The ‘‘execute’’ function above returns a number, not a program, so the program the snippet produces can’t be used to produce a child program.) So, for instance, we’d like to be able to do something like the following example (from Simon), using Matlab code to the two parent programs, Program 1 and Program 2:
#Program 1
if x<1
z = [1,2,3,4,5];
else
for i = 1:5
z(i) = i/x;
end
end
and
#Program 2
for i = 1:10
if x > 5
z(i) = x^i;
else
z(i) = x/i;
end
end
#Child program
for i = 1:10
if x > 5
else
for i = 1:5
z(i) = i/x;
end
end
Where lines 1 and 2 of the child program come from parent 2, and the rest of the lines come from parent 1. Obviously, this cannot work as the child program is garbled nonsense.
But, he says, because s-expressions in lisp correspond to nodes in the AST, we can perform that sort of operation in lisp. For instance (his example), given parent 1 and parent 2 as follows:
#parent 1
(+ (* x y) abs z)
#parent 2
(- (* (+ x z) x) (+ z (/ y x)))
we can swap the s-expression (*x y) from parent 1 with the s-expression (+ z (/ y x)) from parent 2 to get two children:
#child 1
(+ (+ z (/ y x)) abs z) # parent 1, but (+ z (/ y x)) where (* x y) had been.
#child 2
(- (* (+ x z) x) (* x y)) #parent 2, but with (* x y) where (+ z (/ y x)) had been.
This swap can (he says) be performed in lisp by finding an opening parenthesis and a matching closing parenthesis in each parent program, and swapping everything between them in the two programs. As I said, the Conjure Conj talk I linked above gives a similar example.
So though your the functional example is very helpful (especially since one of my goals in looking into this is understanding Julia better), I don’t think it can get me all the way there.
Anyway, I wanted to look into this so I could understand how Julia works better, and even if I don’t find answers to all the questions, I understand Julia a lot better.