The one thing that bothers me is the lack of a separate macro-expansion phaseWhile it is true that there is no macro mechanism in the "define macro" style of CL or Scheme, there are other mechanisms of similar power.
The short reason is: No compilation, no macro. A macro in Lisp, but also in low-level languages like C or assembly, is a piece of code evaluated at compile-time, resulting in another piece of code which is finally compiled. In a pure interpreter there is no compile-time, and thus such a macro doesn't exist.
But the key thing that makes me feel at home in any lisp is knowing that I can effectively re-arrange the syntax of certain operations to forms that I prefer.You can also do that in PicoLisp. The above doesn't mean that you can't programmatically manipulate your code! Basically, there are two possibilities:
1. Use a read macro
In a certain sense, the reader is the "compiler" of PicoLisp. Once an expression is read, it exists as an internal s-expression pointer-structure. If you use a read macro with ` or ~, you can build any code structures you like.
(de foo (A B) `(build-some-code) ~(when (some-condition) (build-more-code) ) ... )You might call that a "micro"-macro ;-)
2. Use 'def' instead of 'de' for a completely evaluated definition
(def 'foo (list (get-parameters) '(some static expression) (some calculated expression) ) )These methods may also be combined. A great example of a typical "macro" in PicoLisp is the 'lazy' function from the Formal Power Series task on Rosetta Code. And if you need help with any concrete examples, don't hesitate ask on the mailing list or IRC channel!
What does backtick do again?` in picolisp is like #. in common lisp. The ~ version splices the read result in, something like ,@ but for the #. reader macro. This article offers a closer look at the distinction between read-time and run-time, and how read-macros can mix 'em up.
But I miss quasiquote...There is a similar mechanism, the function 'fill'. 'fill' takes a template-like pattern, and optional parameters. See (doc 'fill) for examples. The function 'macro' provides a wrapper over 'fill'. As always, (doc 'macro).
Is it possible to create your own reader macro's?Creating reader macros is not built-in in picolisp. However, you can write your own reader if you think it's important. That shouldn't be too hard. It's lisp after all. Here's a brief example to get you started.
There is also a way to switch the Lisp-level 'read' function to a kind of "low-level mode", by calling it with one or two arguments. See (doc 'read).
In that case, 'read' returns atoms (numbers, internal and transient symbols) but not complete s-expressions. Parentheses and other meta-characters are simply returned as transient symbols and can be conveniently processed.
This makes it quite easy to write a customized reader. For example, the JSON "library" on rosettacode.org makes use of this.
Other possibilitesAs there is no compile-time in picolisp, another possibility to precompute stuff is at app load time, before HTTP request loop for example.
If that is not good enough, you can always simulate macroexpansion/compilation by generating picolisp code into a .l file and then load that.