Hi Lee, Personally I think JSwat does the job right in that you can break the code and get a look at local variables. There has also been release a 'debug-repl' which allows you to halt execution and jump into a REPL, like so: http://georgejahad.com/clojure/debug-repl.html. There exists 2 versions, 1 requiring a compile mod.
Finally both CounterClockwise and Enclojure for Netbeans have breakpoint functionality, which is also finding its way into emacs: http://github.com/technomancy/swank-clojure/tree/swank-break. That should give you enough options to inspect locals when the situation arises. Lau On 17 Mar., 16:14, Lee Spector <lspec...@hampshire.edu> wrote: > 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-cloju...), > 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