Help with example from "A Field Guide to Genetic Programming"

5 views
Skip to first unread message

Robert Campbell

unread,
Jul 7, 2009, 8:18:58 AM7/7/09
to clo...@googlegroups.com
I'm trying to write the first basic GP example in this free book:
http://www.lulu.com/items/volume_63/2167000/2167025/2/print/book.pdf

I've gotten a lot of the suppor methods working correctly (like
fitness) but I'm having problem convering the pseudocode on page 14
for generating random expressions to make up my initial population.
Here's what I have so far:

(defn gen-rand-expr [functions terminals max-depth arity method]
(if (or (= max-depth 0) (and (= method :grow) (< (rand) (/ (count
terminals) (+ (count terminals) (count functions))))))
(rand-element terminals)
(let [arg1 (gen-rand-expr functions terminals (- max-depth 1) arity method)
arg2 (gen-rand-expr functions terminals (- max-depth 1) arity method)
func (rand-element functions)]
(func arg1 arg2))))

First, how can I print out the definition of a function in clojure?
For example, if I do (defn add [x y] (+ x y)) how can inspect this
definition, like (show-def add) -> (defn add [x y] (+ x y)). This
would help a lot in debugging the random programs I'm trying to
generate.

Second, I believe the last line is the problem in my code. Let's
assume the function randomly selected was +, it will run (+ 1 2) and
the entire function returns 3 instead of a randomly generated syntax
tree like I need. I then tried '(func arg1 arg2) hoping it would
prevent evaluation, but then it will always just return (func arg1
arg2) which isn't what I need either. I need it to actually return a
syntax tree made up of expressions like (+ 1 2) but unevaluated.

I am guessing I need to start reading and using macros at this point?

Rob

Michel Salim

unread,
Jul 7, 2009, 11:39:12 PM7/7/09
to Clojure


On Jul 7, 8:18 am, Robert Campbell <rrc...@gmail.com> wrote:
> First, how can I print out the definition of a function in clojure?
> For example, if I do (defn add [x y] (+ x y)) how can inspect this
> definition, like (show-def add) -> (defn add [x y] (+ x y)). This
> would help a lot in debugging the random programs I'm trying to
> generate.
>
I don't think that's possible. You can use (doc add), which will give
you the arity signatures of add, as well as the documentation for add,
if there was any. You could, I suppose, include the function body
itself in its documentation, e.g.:

(defn add "(+ x y)" [x y] (+ x y))
#'user/add
user=> (doc add)
-------------------------
user/add
([x y])
(+ x y)
nil

> Second, I believe the last line is the problem in my code. Let's
> assume the function randomly selected was +, it will run (+ 1 2) and
> the entire function returns 3 instead of a randomly generated syntax
> tree like I need. I then tried '(func arg1 arg2) hoping it would
> prevent evaluation, but then it will always just return (func arg1
> arg2) which isn't what I need either. I need it to actually return a
> syntax tree made up of expressions like (+ 1 2) but unevaluated.
>
If your syntax tree is just composed of three-element lists, then
instead of your definition of add, you might want this:

(defn add [x y] `(+ ~x ~y))

HTH,

--
Michel

Timothy Pratley

unread,
Jul 8, 2009, 12:06:40 AM7/8/09
to Clojure
It seems to me you want:
user=> (list + 1 2)
(#<core$_PLUS___4006 clojure.core$_PLUS___4006@1acd47> 1 2)

As opposed to:
user=> '(+ 1 2)
(+ 1 2)

Regarding examining a function, contrib has some helpers written by
Chris
user=> (use 'clojure.contrib.repl-utils)
(source func)
(show func)
In your case source wont be useful as the function is generated not
read from source. The output from show is a bit opaque to me so not
sure if it is useful to you.

I think once it is compiled a function is not easy to examine... so as
you alluded to the best alternative would be to keep the AST?

Regards,
Tim.

kyle smith

unread,
Jul 8, 2009, 12:31:19 AM7/8/09
to Clojure
> I am guessing I need to start reading and using macros at this point?

I also wrote something to do symbolic regression. I used plain
functions to manipulate quoted trees, and one macro to wrap the
expression in a fn and eval.

Robert Campbell

unread,
Jul 8, 2009, 8:37:26 AM7/8/09
to clo...@googlegroups.com
> It seems to me you want:
> user=> (list + 1 2)
> (#<core$_PLUS___4006 clojure.core$_PLUS___4006@1acd47> 1 2)

That looks like what I'm after. When I run a test, however, it doesn't
behave properly:

user> (def my-func (list + 1 2))
#'user/my-func
user> (my-func)
; Evaluation aborted.
clojure.lang.PersistentList cannot be cast to clojure.lang.IFn

Richard Newman

unread,
Jul 8, 2009, 1:22:04 PM7/8/09
to clo...@googlegroups.com
> That looks like what I'm after. When I run a test, however, it doesn't
> behave properly:

You'll want to either eval the expression, or apply the first item in
the list to the rest:

user=> (eval (list + 1 2))
3
user=> (let [form (list + 1 2)]
(when (not (empty? form))
(apply (first form) (rest form))))
3

Robert Campbell

unread,
Jul 8, 2009, 1:57:35 PM7/8/09
to clo...@googlegroups.com
That's it, that's exactly what I needed to complete this example. I'm
pretty pumped because you guys have shown me a way to do it without
macros and without manually managing a quoted tree structure.

If it's okay, could somebody explain the difference between what's
happening here:

user> (def my-func (list + 1 2))
#'user/my-func
user> (my-func)
; Evaluation aborted.

and here:

user> (def my-func (list + 1 2))
#'user/my-func
user> (eval my-func)
3

I don't really understand how:
user>(my-func) is NOT eval on my-func in the REPL. My understanding is
the first item in the list is treated as a function, with the rest of
the list passed as arguments. Wouldn't the REPL just be calling eval
internally on everything you type in?

John Harrop

unread,
Jul 8, 2009, 6:06:37 PM7/8/09
to clo...@googlegroups.com
On Wed, Jul 8, 2009 at 1:57 PM, Robert Campbell <rrc...@gmail.com> wrote:
If it's okay, could somebody explain the difference between what's
happening here:

user> (def my-func (list + 1 2))
#'user/my-func
user> (my-func)
; Evaluation aborted.

and here:

user> (def my-func (list + 1 2))
#'user/my-func
user> (eval my-func)
3

I don't really understand how:
user>(my-func) is NOT eval on my-func in the REPL. My understanding is
the first item in the list is treated as a function, with the rest of
the list passed as arguments. Wouldn't the REPL just be calling eval
internally on everything you type in?
 
Not every expression is a function, even if most are function calls.

Any expression can be evaluated with eval. To call something as a function, though, it has to be something invokable. A list, even a list of a function and two values, isn't. An actual function is, as produced by defn or fn or #(). So are sets, maps, and vectors, which will look up the argument key or index:

user=> (#{'x 'y} 'x)
x
user=> (#{'x 'y} 'z)
nil
user=> ({:key 'val} :key)
val
user=> ({:key 'val} 3)
nil
user=> (['a 'b 'c] 0)
a
user=> (['a 'b 'c] 2)
c
user=> (['a 'b 'c] 3)
#<CompilerException java.lang.ArrayIndexOutOfBoundsException: 3 (NO_SOURCE_FILE:0)>

And keywords can be invoked to do set and map lookups:

user=> (:key {:key 'val})
val
user=> (:x {:key 'val})
nil
user=> (:key #{:key})
:key
user=> (:x #{:key})
nil

Last but not least, there's ., .., .methName, Class., Class/staticMeth, Class/staticField, and other variations on this theme to interact with Java classes. And maybe one or two things I'm forgetting. :)

Richard Newman

unread,
Jul 8, 2009, 6:21:06 PM7/8/09
to clo...@googlegroups.com
> Any expression can be evaluated with eval.

As, indeed, can self-evaluating forms:


user=> (eval 3)
3
user=> (eval (eval (eval (list + 1 2))))
3
user=> (eval :foo)
:foo
user=> (eval '+)
#<core$_PLUS___3949 clojure.core$_PLUS___3949@1d05c9a1>
user=> (eval 'eval)
#<core$eval__4610 clojure.core$eval__4610@4ef5c3a6>


This kind of fiddling around in a REPL is very enlightening.

Timothy Pratley

unread,
Jul 8, 2009, 7:47:40 PM7/8/09
to Clojure
> user> (def my-func (list + 1 2))
> #'user/my-func
> user> (my-func)

A list is not a function. Expanded: ((list + 1 2)) The first item in
the outer list is a list, it is not a function. So to invoke the
function you need to get it using first. Eval call on a list is
evaluating a list, and the first item is a function so yup that works.
It was bad (confusing) advice from me to store it like this really.
You could just as easily used something like (let [my-fun {:fn
+, :args [1 2]}] (apply (:fn my-fun) (:args my-fun))) The list
approach is slightly more compact in that you can use eval and it
'looks' more lispy? Just a note, apply here isn't doing anything
magical it is just unpacking the arguments to give (+ 1 2).


> user> (def my-func (list + 1 2))
> #'user/my-func
> user> (eval my-func)
> 3

> I don't really understand how:
> user>(my-func) is NOT eval on my-func in the REPL.
> My understanding is
> the first item in the list is treated as a function, with the rest of
> the list passed as arguments. Wouldn't the REPL just be calling eval
> internally on everything you type in?

Yes they are both evaluated, but they are different expressions:
((+ 1 2))
vs (+ 1 2)


Regards,
Tim.
Reply all
Reply to author
Forward
0 new messages