gpt4 book ai didi

unit-testing - 宏约定和最佳实践的 Lisp 单元测试

转载 作者:太空宇宙 更新时间:2023-11-03 18:33:28 24 4
gpt4 key购买 nike

我发现很难对宏扩展进行推理,并且想知道测试它们的最佳实践是什么。

因此,如果我有一个宏,我可以通过 macroexpand-1 执行一级宏扩展。

(defmacro incf-twice (n)
`(progn
(incf ,n)
(incf ,n)))

例如

(macroexpand-1 '(incf-twice n))

评估为

(PROGN (INCF N) (INCF N))

把它变成宏测试似乎很简单。

(equalp (macroexpand-1 '(incf-twice n))
'(progn (incf n) (incf n)))

是否有组织宏测试的既定惯例?另外,是否有用于总结 s 表达式之间差异的库?

最佳答案

一般来说,测试宏并不是 Lisp 和 Common Lisp 的强项之一。 Common Lisp(和一般的 Lisp 方言)使用过程宏。宏可以依赖于运行时上下文、编译时上下文、实现等等。它们也可能有副作用(比如在编译时环境中注册东西,在开发环境中注册东西等等)。

所以有人可能想测试一下:

  • 生成正确的代码
  • 生成的代码确实做了正确的事情
  • 生成的代码在代码上下文中实际工作
  • 在复杂宏的情况下,宏参数实际上被正确解析。想想 loopdefstruct,......宏。
  • 宏检测到格式错误的参数代码。同样,想想像 loopdefstruct 这样的宏。
  • 副作用

从上面的列表可以推断出在开发宏时最好尽量减少所有这些问题区域。但是:那里确实有非常复杂的宏。真的很可怕。尤其是那些习惯于实现新领域特定语言的人。

使用类似equalp 的东西来比较代码只适用于相对简单的宏。宏通常会引入新的、未保留的和独特的符号。因此 equalp 将无法使用这些。

例子:(rotatef a b) 看似简单,展开其实很复杂:

CL-USER 28 > (pprint (macroexpand-1 '(rotatef a b)))

(PROGN
(LET* ()
(LET ((#:|Store-Var-1234| A))
(LET* ()
(LET ((#:|Store-Var-1233| B))
(PROGN
(SETQ A #:|Store-Var-1233|)
(SETQ B #:|Store-Var-1234|))))))
NIL)

#:|Store-Var-1233| 是一个符号,它是未驻留的,由宏新创建的。

另一种具有复杂扩展的简单宏形式是(defstruct s b)

因此需要一个 s 表达式模式匹配器来比较扩展。有一些可用的,它们在这里很有用。需要在测试模式中确保生成的符号在需要时是相同的。

还有 s-expression 差异工具。例如diff-sexp .

关于unit-testing - 宏约定和最佳实践的 Lisp 单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34571055/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com