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 |