4

我在闲逛 PicoLisp,发现自己对如何编写传统上由宏处理的元编程函数(在其他 lisp 方言中)感到困惑。对我来说最大的担忧是我看不到如何防止变量名隐藏。回顾元编程 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") ) ) )

我已经用 call 测试了每一个(let "Args" * (mapeach N (1 2 3) ("Args" N N)))。正如预期的那样,PicoLisp 解释器(以 command 开头pil +)遇到段错误并崩溃。我认为这是因为mapeach's"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),这同样阻止了段错误。如果我没有将定义与正确调用分开的错误调用,则总是会发生段错误。

这最终导致两个问题:

  1. 如何防止名称隐藏?显然,这些例子在这方面并不成功。
  2. 为什么对 map@ 的调用不会导致段错误?
4

1 回答 1

4

根据这个“瞬态符号的索引在加载源文件之前和之后自动清除,或者可以使用 ==== 函数显式重置”。它没有指定在常规 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不在同一个文件中。

为了解决我的问题的两个部分:

  1. 您可以通过在不同文件中使用瞬态符号或随后调用====.
  2. 这些调用可能有效,因为调试器清除了包含瞬态符号的索引。
于 2019-04-16T17:28:28.380 回答