Hi Johan, > First off, I'm confused about what the correct way of doing local exits. > There's no "return" or "return-from" -- instead the closest thing I've found > is "quit", which is sort of akin to "error" in CL
Correct. There is no 'return' function jumping directly out of a nested structure. There are, however, 'catch' and 'throw', which implement the same mechanism (cleaning up all necessary stuff before doing the exit) - just not syntactically as neat as a simple 'return'. I use NIL as the catch tag in such cases, e.g. (de foo (Args) (catch NIL (while (something) (let (A (bar) B (mumble)) (racker (for I A (when (lt0 (+ I B)) (throw) ) ) ) ) ) ) ) Here (throw) corresponds to a (return). To return a value like (return 7) do (throw NIL 7). The reason for not having a 'return' function is that it has to do a lot of cleanup till it reaches the exit (unbind variables, close files and other dynamic environments). This is initialized and set up by 'catch'. When a function starts to run, the interpreter does not know yet that there might be a call to 'return' somewhere deeply nested inside. So it would need to setup the catch environment for *every* function. This would be too expensive, as most functions will never call 'return'. Instead, it is done the PicoLisp way: Let the programmer be in control! Just insert '(catch NIL' at the beginning of a function (or at any other place). If you insist, you can create your own return function: (de return (Val) (throw NIL Val) ) The '(catch NIL' is still needed though. 'quit' is similar to 'throw'. It throws an error message instead of a tag, and is triggered internally also when an error occurs, which then can be caught with '(catch '("Message 1" "Message 2") ... > Then there's the conditional exits in "for", "do" and "loop" which presents > a real problem if you wish to terminate the loop from within a sub-clause: > > (for X (1 2 3 4 5) > (let Y (mumble-mumble X) > (NIL Y (println "this doesn't work")))) Yes. As also pointed out by Bruno, the 'T' and 'NIL' exit clauses must be on the top level of the body. Usually code can be rearranged this way. If not, catch/throw can be used here too. > I'm also a pathological meta-programmer, and the lack of macros doesn't > bother me as much as I thought it would. However, one thing I miss from > other lisps is a way of expanding macros. How would I go on about doing that > in PicoLisp? For one thing, there are read-macros which are expanded at read-time. Then, there is - also pointed out by Bruno - 'fill' and 'macro' which may be used to build and execute expressions at runtime. 'macro' is rather seldom used, as it introduces quite some overhead in an interpreted system. The way to go for meta-programming is to use FEXPRs. Examples are many in the PicoLisp package itself, or at https://software-lab.de/doc/faq.html#macros or http://rosettacode.org/wiki/Extend_your_language#PicoLisp —Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe