Metaprogramming 101
Rewriting Common Lisp macros as PicoLisp functions
I came across a cute little Common Lisp macro, mapeach. Naturally, I wanted it to play with it in PicoLisp. The most straightforward translation (for me) was:
(de mapeach "Args"
(let [(@Var @Lst . Body) "Args"]
(macro
(mapcar
'((@Var) ^ Body)
@Lst )
It works great for single variable expressions.
: (mapeach N (1 2 3) (* N N)) -> (1 4 9)Multiple vars will break it, however.
Variations
There are many ways we could write 'mapeach'. How about,
(de mapeach "Args"
(mapcar
(cons (cons (car "Args")) (cddr "Args"))
(eval (cadr "Args")) ) )
The 'cons'es are a little less expensive than the full macro.Another could be:
(de mapeach "Args"
(mapcar
'(("E")
(bind (car "Args")
(set (car "Args") "E")
(run (cddr "Args")) ) )
(eval (cadr "Args")) ) )
This is a bit longer, but needs no consing at all.And if we define this syntax for multiple variables:
(mapeach (X Y) '(a b c) '(d e f) (foo ...we can write
(de mapeach "Args"
(let "Vars" (pop '"Args")
(apply mapcar
(mapcar eval (cut (length "Vars") '"Args"))
(cons "Vars" "Args") ) ) )
: (mapeach (X Y) (1 2 3) (4 5 6)
(* X Y) )
-> (4 10 18)
Even Cuter!
An even more "cute" solution would be if we could avoid the parameter argument completely. The natural way for this in PicoLisp is the implied parameter @.We might define
(de map@ "Args"
(mapcar
'(("E") (and "E" (run (cdr "Args")))) # 'and' sets '@'
(eval (car "Args")) ) )
With that, you can call
: (map@ (1 2 3) (* @ @)) -> (1 4 9)As a side note, there's a clever use of 'and' here, which is fairly common in PicoLisp code. Always have in mind the back of your mind that 'and' sets the value of @ (just like the other "flow functions".
A more traditional way would be,
'(("E") (let @ "E" (run (cdr "Args"))))
i.e. explicitly bind the symbol with 'let'.But why make it so complicated? We can have our "lambda" expression directly (and dynamically) bind the @ symbol.
'((@) (run (cdr "Args")))With that, the whole function is
(de map@ "Args"
(mapcar
'((@) (run (cdr "Args")))
(eval (car "Args")) ) )
https://picolisp.com/wiki/?metaprogramming101
| 09dec20 | erik |
