syntax - Common Lisp 宏语法关键字 : what do I even call this?

标签 syntax macros common-lisp keyword

为了自己回答这个问题,我查阅了On LispPractical Common Lisp和SO文件,但这些尝试因我无法说出我感兴趣的概念。如果有人能告诉我此类事物的规范术语,我将不胜感激。

这个问题可能最好通过一个例子来解释。假设我想在 Common Lisp 中实现 Python 风格的列表推导式。在 Python 中我会这样写:

[x*2 for x in range(1,10) if x > 3]

所以我首先写下:

(listc (* 2 x) x (range 1 10) (> x 3))

然后定义一个宏,将上面的内容转换为正确的理解。到目前为止一切顺利。

但是,对于尚未熟悉 Python 列表推导式的读者来说,该表达式的解释是不透明的。我真正希望能够写的是以下内容:

(listc (* 2 x) for x in (range 1 10) if (> x 3)) 

但我还没有找到 Common Lisp 的术语。看起来 loop 宏正是做这种事情的。它叫什么,我该如何实现它?我尝试宏扩展示例循环表达式以查看它是如何组合在一起的,但生成的代码难以理解。有人能引导我走向正确的方向吗?

提前致谢。

最佳答案

嗯,for 本质上是解析作为其主体提供的表单。例如:

(defmacro listc (expr &rest forms)
  ;; 
  ;;
  ;; (listc EXP for VAR in GENERATOR [if CONDITION])
  ;;
  ;;
  (labels ((keyword-p (thing name)
             (and (symbolp thing)
                  (string= name thing))))
    (destructuring-bind (for* variable in* generator &rest tail) forms
      (unless (and (keyword-p for* "FOR") (keyword-p in* "IN"))
        (error "malformed comprehension"))
      (let ((guard (if (null tail) 't
                       (destructuring-bind (if* condition) tail
                         (unless (keyword-p if* "IF") (error "malformed comprehension"))
                         condition))))
        `(loop 
            :for ,variable :in ,generator 
            :when ,guard 
            :collecting ,expr)))))


(defun range (start end &optional (by 1))
  (loop
     :for k :upfrom start :below end :by by
     :collecting k))

除了我使用的黑客“解析器”之外,这个解决方案还有一个缺点,在 Common Lisp 中不容易解决,即中间列表的构造,如果你想链接你的推导式:

(listc x for x in (listc ...) if (evenp x))

由于在 common lisp 中没有与 yield 等价的道德概念,因此很难创建不需要完全实现中间结果的设施。解决这个问题的一种方法可能是在 listc 的扩展器中对可能的“生成器”形式的知识进行编码,因此扩展器可以优化/内联基本序列的生成,而无需构建整个中间体在运行时列出。

另一种方法可能是引入 "lazy lists" (链接指向方案,因为在 common lisp 中没有等效的工具 - 你必须首先构建它,尽管它不是特别难)。

此外,您始终可以查看其他人的代码,特别是如果他们尝试解决相同或类似的问题,例如:

关于syntax - Common Lisp 宏语法关键字 : what do I even call this?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7129776/

相关文章:

java - 我在while循环中收到了意外 token

syntax - 我可以为自己覆盖 Lua 表的返回值吗?

ios - 具有获取 NSString 条件的宏

ecmascript-6 - Parenscript 中的 ES6 样式类

lisp - 将点对转换为 LISP 中的双元素列表

c++ - 语法命题 : readability of templated type declarations

python - Python 中 x = 'y' 'z' 的底层是什么?

c++ - 通过宏从函数定义(并声明和使用)全局变量

c - C 预处理器的对面 "stringification"

lisp - ACT-r : assigning a chunk as buffer slot value in a production rule