亲爱的大家,我现在有了一个初步的宏
(defmacro key-if(test &key then else)
`(cond (,test
,then)
(t,else)))
它现在可以正常工作了
> (key-if (> 3 1) :then 'ok)
OK
> (key-if (< 5 3) :else 'ok)
OK
> (key-if (> 3 1) :else 'oops)
NIL
> (key-if (> 3 1) :else 'oops :then 'ok)
OK
现在我想扩展它一点,这意味着我想有任意数量的参数后跟 :then
或 :else
(关键字),所以它会像
> (key-if (> 3 1) :then)
NIL
> (key-if (> 3 1) :else 'oops :then (print 'hi) 'ok)
HI
OK
所以我现在停留在这一点上,我对 Lisp 宏有点陌生。我可以考虑将 &rest
用于此扩展,但不知道如何操作,所以我真的需要您提供有关如何使此扩展正常工作的想法。
非常感谢。
最佳答案
我假设您正在使用一些 Common Lisp 实现。
the standard lambda lists used by DEFMACRO 不直接支持这种参数解析风格.你认为你必须自己解析参数是正确的(你可以使用 (test &rest keys-and-forms)
来捕获 TEST,但是提取 :ELSE 和 :THEN 部分将是正确的给你。
我不是 super (Common-)Lisper,但您在这里发明的语法似乎非常不合时宜。第一个提示是宏 lambda 列表不支持你想要的。此外,已经有标准的替代方案,其输入的原始字符长度相同或更短(通过使用 Emacs 中的 paredit 等结构编辑器可以减少输入开销)。
(key-if blah :then foo bar) ; multiple then, no else
(when blah foo bar) ; standard
(key-if blah :else baz quux) ; no then, multiple else
(unless blah baz quux) ; standard
(key-if blah :then foo :else baz quux) ; one then, multiple else
(if blah foo (progn baz quux)) ; standard
(cond (blah foo) (t baz quux))
(key-if blah :then foo bar :else baz) ; multiple then, one else
(if blah (progn foo bar) baz) ; standard
(cond (blah foo bar) (t baz))
(key-if blah :then foo bar :else baz quux) ; multiple then, multiple else
(if blah (progn foo bar) (progn baz quux)) ; standard
(cond (blah foo bar) (t baz quux)) ; even shorter
(key-if blah :else baz quux :then foo bar) ; multiple else before multiple then
(if (not blah) (progn baz quux) (progn foo bar)) ; only standard variation that is longer
(cond ((not blah) baz quux) (t foo bar) ; standard, shorter
Common Lisp 宏是非常强大的代码模板引擎,但这种特殊用法让我觉得您只是不太适应 Common Lisp 中的标准样式和习语。无论您使用哪种语言,采用“本地”风格和习语“顺其自然”几乎总是一个好主意,而不是从您更熟悉的其他语言中引入风格和习语。
关于lisp - 让我的 lisp 代码更健壮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1774360/