如何编写不使用其参数隐藏变量的 PicoLisp 函数
How to write a PicoLisp function that does not shadow variables with it's parameters
我正在闲逛 PicoLisp,发现自己对如何编写传统上用宏(在其他 lisp 方言中)处理的元编程函数感到困惑。我最担心的是我不知道如何防止变量名隐藏。查看 Metaprogramming 101 中的示例,如果有的话,只会让我更加困惑。
有关如何实现函数 mapeach
的示例,如链接文章中所示:
[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") ) ) )
我已经通过调用 (let "Args" * (mapeach N (1 2 3) ("Args" N N)))
测试了其中的每一个。正如预期的那样,PicoLisp 解释器(以命令 pil +
启动)遇到段错误并崩溃。我认为这是因为 mapeach
的 "Args"
遮盖了调用点定义的 "Args"
。
我还尝试了他们对 map@
的两种实现(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")) ) )
我使用 (let "Args" * (map@ (1 2 3) ("Args" @ @)))
来测试每个实现。奇怪的是,我第一次测试第一个实现时,不仅 没有 段错误,而且还产生了正确的结果 (1 4 9)
。随后的每个测试都会导致段错误。为清楚起见,提示中的片段:
: (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)
我相信调用(当时的)未定义函数 mapeach
以某种方式阻止了段错误,我也尝试了 (ooga booga)
,这同样阻止了段错误。如果我没有将定义与正确调用分开的错误调用,则总是会发生段错误。
这最终会导致 2 个问题:
- 如何防止名称隐藏?显然,这些例子在这方面没有成功。
- 为什么对 map@ 的调用 而不是 会导致段错误?
According to this"The index for transient symbols is cleared automatically before and after loading a source file, or it can be reset explicitly with the ==== function"。它没有指定在常规 REPL 使用期间自动清除它的任何方式,这是我测试它的上下文。
此代码运行正常:
[de mapeach "Args" # expression
(let [(@Var @List . @Body) "Args"]
(macro
(mapcar
'((@Var) . @Body)
@List ]
(====)
(let "Args" * (mapeach N (1 2 3) ("Args" N N)))
即使不调用 ====
,它也能按预期运行,但前提是对 mapeach
的调用不在同一个文件中。
解决我问题的两个部分:
- 您可以通过在不同的文件中使用瞬态符号或随后调用
====
. 来防止名称隐藏
- 这些调用可能有效,因为调试器清除了包含瞬态符号的索引。
我正在闲逛 PicoLisp,发现自己对如何编写传统上用宏(在其他 lisp 方言中)处理的元编程函数感到困惑。我最担心的是我不知道如何防止变量名隐藏。查看 Metaprogramming 101 中的示例,如果有的话,只会让我更加困惑。
有关如何实现函数 mapeach
的示例,如链接文章中所示:
[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") ) ) )
我已经通过调用 (let "Args" * (mapeach N (1 2 3) ("Args" N N)))
测试了其中的每一个。正如预期的那样,PicoLisp 解释器(以命令 pil +
启动)遇到段错误并崩溃。我认为这是因为 mapeach
的 "Args"
遮盖了调用点定义的 "Args"
。
我还尝试了他们对 map@
的两种实现(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")) ) )
我使用 (let "Args" * (map@ (1 2 3) ("Args" @ @)))
来测试每个实现。奇怪的是,我第一次测试第一个实现时,不仅 没有 段错误,而且还产生了正确的结果 (1 4 9)
。随后的每个测试都会导致段错误。为清楚起见,提示中的片段:
: (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)
我相信调用(当时的)未定义函数 mapeach
以某种方式阻止了段错误,我也尝试了 (ooga booga)
,这同样阻止了段错误。如果我没有将定义与正确调用分开的错误调用,则总是会发生段错误。
这最终会导致 2 个问题:
- 如何防止名称隐藏?显然,这些例子在这方面没有成功。
- 为什么对 map@ 的调用 而不是 会导致段错误?
According to this"The index for transient symbols is cleared automatically before and after loading a source file, or it can be reset explicitly with the ==== function"。它没有指定在常规 REPL 使用期间自动清除它的任何方式,这是我测试它的上下文。
此代码运行正常:
[de mapeach "Args" # expression
(let [(@Var @List . @Body) "Args"]
(macro
(mapcar
'((@Var) . @Body)
@List ]
(====)
(let "Args" * (mapeach N (1 2 3) ("Args" N N)))
即使不调用 ====
,它也能按预期运行,但前提是对 mapeach
的调用不在同一个文件中。
解决我问题的两个部分:
- 您可以通过在不同的文件中使用瞬态符号或随后调用
====
. 来防止名称隐藏
- 这些调用可能有效,因为调试器清除了包含瞬态符号的索引。