I am idly exploring PicoLisp, and find myself perplexed about how to write meta-programming functions that would traditionally be handled with macros (in other lisp dialects). The biggest source of concern for me is that I do not see how I can prevent variable name shadowing. Reviewing the examples in Metaprogramming 101 has, if anything, just left me more confused.
Examples on how to implement the function mapeach, as seen in the linked article:
[de mapeach "Args" # expression
(let [(@Var @List . @Body) "Args"]
(macro
(mapcar
'((@Var) . @Body)
@List ]
(de mapeach "Args"
(mapcar
(cons (cons (car "Args")) (cddr "Args"))
(eval (cadr "Args")) ) )
(de mapeach "Args"
(mapcar
'(("E")
(bind (car "Args")
(set (car "Args") "E")
(run (cddr "Args")) ) )
(eval (cadr "Args")) ) )
(de mapeach "Args"
(let "Vars" (pop '"Args")
(apply mapcar
(mapcar eval (cut (length "Vars") '"Args"))
(cons "Vars" "Args") ) ) )
I have tested each of these with the call (let "Args" * (mapeach N (1 2 3) ("Args" N N))). As expected, the PicoLisp interpreter (started with the command pil +) experiences a segfault and crashes. I assume this is because mapeach's "Args" shadows the "Args" defined at call point.
I also tried both of their implementations of map@ (the "cuter" alternative to mapeach).
(de map@ "Args"
(mapcar
'(("E") (and "E" (run (cdr "Args")))) # 'and' sets '@'
(eval (car "Args")) ) )
(de map@ "Args"
(mapcar
'((@) (run (cdr "Args")))
(eval (car "Args")) ) )
I used (let "Args" * (map@ (1 2 3) ("Args" @ @))) to test each of those implementations. Bizarrely, the first time I tested the first implementation, not only did it not segfault, it actually produced the correct result (1 4 9). Each subsequent test has resulted in a segfault. For clarity, the snippet from the prompt:
: (de map@ "Args"
(mapcar
'(("E") (and "E" (run (cdr "Args")))) # 'and' sets '@'
(eval (car "Args")) ) )
-> map@
: (let "Args" * (mapeach N (1 2 3) ("Args" N N)))
!? (mapeach N (1 2 3) ("Args" N N))
mapeach -- Undefined
?
: (let "Args" * (map@ (1 2 3) ("Args" @ @)))
-> (1 4 9)
I believe that the segfault was somehow prevented by the call to the (then) undefined function mapeach, I also tried (ooga booga), which similarly prevented the segfault. If I do not have the erroneous call separating the definition from the proper call, a segfault always occurs.
This ultimately culminates in 2 questions:
- How can I prevent name shadowing? Clearly the examples do not succeed in that regard.
- Why does that call to map@ not result in a segfault?