【问题标题】:How to write a PicoLisp function that does not shadow variables with it's parameters如何编写不使用参数隐藏变量的 PicoLisp 函数
【发布时间】:2019-04-15 21:47:48
【问题描述】:

我在闲逛 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)。随后的每个测试都导致了段错误。为清楚起见,提示中的 sn-p:

:  (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@ 的调用会导致段错误?

【问题讨论】:

  • 也许使用匿名(瞬态)符号? (software-lab.de/doc/ref.html#symbol)
  • 这是我困惑的一部分,"Args" 一个短暂的符号。我尝试生成一个使用匿名瞬态符号作为参数列表的函数,但它并没有真正起作用。但是,我认为更好地理解瞬态符号可能是解决我的问题的关键。我相信答案是“瞬态符号的索引在加载源文件之前和之后会自动清除,或者可以使用 ==== 函数显式重置”。在普通 REPL 使用期间,它似乎不会自动重置。 software-lab.de/doc/ref.html#transient-io

标签: scope lisp dynamic-scope picolisp


【解决方案1】:

According to this "临时符号的索引在加载源文件之前和之后会自动清除,或者可以使用 ==== 函数显式重置"。它没有指定在常规 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. 这些调用可能有效,因为调试器清除了包含临时符号的索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多