I apologize for the length of this message, but I've run into a problem that I 
think I might approach in any of several ways, each of which leads to questions 
about things that I'd like to know more about in any event. Some are dev 
environment questions and some (re: circular lists near the end) are core 
Clojure language questions.

The root problem is that I think I have an infinite loop somewhere in my code 
and I'm having a hard time tracking it down. My system has a lot of randomness 
in it and I've been unable to produce a repeatable or minimal example, but in 
many full-scale runs I eventually get a hang that smells like an infinite loop. 
I found one that I tracked down to some recursive zipper code, and I fixed 
that, but there's at least one more and I can't find it. One of the reasons 
this is particularly tricky is that I'm dynamically generating and executing 
lots of calls in random/evolved orders with random/evolved arguments, so 
unexpected sequences of events can arise. (And they do arise, which is the 
point! :-)

In Common Lisp I would wait until I think I'm in trouble, break execution with 
a keyboard interrupt, look at the function call stack (and local vars, if I'm 
in a nice CL environment), and probably figure it out pretty quickly.

What would experienced Clojurians suggest in a situation like this?

Is there is a way to break and look around under slime? I just finally got 
slime working with Clojure (THANKS to Lau Jens, 
http://www.bestinclass.dk/index.php/2009/12/clojure-101-getting-clojure-slime-installed/),
 but I don't yet know my way around it. Can anyone recommend a good concise 
description of all of the relevant key commands? I've never used slime much for 
Common Lisp either -- I've used mostly IDEs like MCL and various lisp machines 
way back in the last century -- so I need to start near the beginning on slime. 
Knowing that I could break and examine state would certainly motivate that.

In general I've been running a REPL in a separate terminal window using the clj 
script that comes with ClojureX (on macs running OS X 10.6.2). I don't know how 
to force a break or get a break loop in this environment but when I hit an 
error I can do (.printStackTrace *e) and this does show me some of my own 
function calls amid the other stuff. Even though this is pretty minimal it has 
been very helpful at times. Two problems with this, however: 1) I can only get 
this from an error; I don't know how to force a break so I can look at this 
when I seem to be stuck in a loop, and 2) The stack trace info is always 
elided, with lines saying something like "... 31 more". I want all the trace 
information that it can give me, but I've been unable to figure out how to keep 
it from eliding. I've tried to force clj-initiated runs to break by sending 
signals to the java process from the Mac OS X Activity Monitor app, but 
everything that I have tried (e.g. SIGINT) either does nothing or kills the 
whole process. Is there a signal that I could sent to abort execution but not 
quit java, as happens with errors,  so that I could look at a backtrace? Is 
there a handler that I could add to my code to allow this to happen? It'd only 
help if it allowed me to see what else was going on when the signal was 
received; if it only told me that the error was from a signal arriving then 
that would defeat the purpose.

I've also been doing some runs under MCLIDE, with help from Terje Norderhaug, 
and there I can indeed issue a break from a menu and get a backtrace of 
sorts... but so far I have not been able to get a backtrace that shows me what 
I need -- that is, I don't see any of my own functions, presumably because the 
break changed the context... I'm not sure what's going on there. I've also 
briefly experimented with Eclipse/Counterclockwise, but found Eclipse fairly 
confusing in general... but does it provide a better approach to 
breaking/exploring running code? If so then perhaps I should give that another 
shot.

An alternative: Is there a way to watch my running Clojure program without 
breaking it, that is to observe the recent call history (of my own definitions, 
either all of them or specifically marked ones) from outside the process? I can 
think of some clumsy ways to roll my own version of this, e.g. using trace and 
sending the trace output to a file, but I don't think this will be practical 
because I generally only get these errors after long stretches of intensive 
computation that will involve many many calls to the potentially problematic 
functions. So I think there'll be too much trace output to save on disk, and 
the slowdown from tracing all of the calls may prevent me from ever reaching a 
problematic state (although I haven't tried this to be sure of the timing). I 
guess I could keep a bounded trace on disk but maintaining the bound would slow 
things even more... So this doesn't feel like the best approach. Might there be 
-- wishful thinking, I know -- some already-existing way to eavesdrop on a 
running Clojure program dynamically, from another process, and see what 
functions are being called?

Some of this is complicated by the fact that I'm running multiple threads in 
Clojure while I never do so under Common Lisp... So there's the question of 
which threads get interrupted and which stacks get looked at. But the backtrace 
produced by (.printStackTrace *e) has nonetheless produced useful clues so I'm 
hopeful...

One last set of questions stemming from this problem concerns circular lists. 
In Common Lisp my unintentional infinite loops have often stemmed from 
accidental circular lists (which were created by dynamically random/evolved 
sequences of list-manipulation instructions). I know how these can arise in 
Common Lisp and I also know how to prevent them there, generally with lots of 
(usually unnecessary and expensive) list copying. In Clojure I'm not even sure 
if/how such lists can arise, and I'd be interested in any general comments that 
anyone has on that. To make matters more confusing I'm not sure how to copy a 
list, to prevent such problems if they are indeed possible. I realize that 
copying is generally not necessary in Clojure because of immutability, but if 
one wants to copy a list how can one do it?

Thanks for your patience in reading this. I'd appreciate any feedback on any 
parts of it.

And in spite of the problems listed above I'm having a great time in the 
Clojureverse!

 -Lee



--
Lee Spector, Professor of Computer Science
School of Cognitive Science, Hampshire College
893 West Street, Amherst, MA 01002-3359
lspec...@hampshire.edu, http://hampshire.edu/lspector/
Phone: 413-559-5352, Fax: 413-559-5438

Check out Genetic Programming and Evolvable Machines:
http://www.springer.com/10710 - http://gpemjournal.blogspot.com/

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to