Syntax 公共lisp宏语法关键字:我该怎么称呼它?
为了自己回答这个问题,我查阅了Lisp、实用公共Lisp和SO文档,但是由于我无法说出我感兴趣的概念,这些尝试都失败了。如果有人能告诉我这类事情的标准术语,我将不胜感激 这个问题最好用一个例子来解释。假设我想在CommonLisp中实现Python风格的列表理解。我将用Python编写:Syntax 公共lisp宏语法关键字:我该怎么称呼它?,syntax,macros,common-lisp,keyword,Syntax,Macros,Common Lisp,Keyword,为了自己回答这个问题,我查阅了Lisp、实用公共Lisp和SO文档,但是由于我无法说出我感兴趣的概念,这些尝试都失败了。如果有人能告诉我这类事情的标准术语,我将不胜感激 这个问题最好用一个例子来解释。假设我想在CommonLisp中实现Python风格的列表理解。我将用Python编写: [x*2 for x in range(1,10) if x > 3] 因此,我首先写下: (listc (* 2 x) x (range 1 10) (> x 3)) 然后定义一个宏,将上述内
[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))
但是我还没有找到这个常用的Lisp术语。似乎循环
宏正是这样做的。它叫什么,我如何实现它?我尝试对一个循环表达式示例进行宏扩展,以查看它是如何组合在一起的,但生成的代码无法理解。有人能给我指引正确的方向吗
提前感谢。好吧,它的基本功能是解析作为其主体提供的表单。例如:
(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))
除了我使用的黑客“解析器”之外,这个解决方案还有一个缺点,这在普通lisp中是不容易解决的,即如果您想链接您的理解,那么中间列表的构造:
(listc x for x in (listc ...) if (evenp x))
由于在common lisp中没有与yield
道德等价的工具,因此很难创建一个不需要完全实现中间结果的工具。一种解决方法可能是在listc
的扩展器中编码可能的“生成器”形式的知识,以便扩展器可以优化/内联基本序列的生成,而不必在运行时构建整个中间列表
另一种方法可能是引入(链接点到scheme,因为在common lisp中没有等效的工具——您必须首先构建它,尽管这并不特别困难)
此外,您可以随时查看其他人的代码,特别是当他们试图解决相同或类似的问题时,例如:
(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))
- (哪个做了懒惰列表的事情)
Series是处理序列的框架。在大多数情况下,序列可以不存储中间值。宏是代码转换器 有几种实现宏语法的方法:
- 解构
(loop for i from 0 when (oddp i) collect i)
- 解析
(infix (2 + x) * (3 + sin (y)))
宏实现需要实现中缀解析器并返回前缀表达式:
(* (+ 2 x) (+ 3 (sin y)))
- 基于规则的
(loop for i from 0 when (oddp i) collect i)
见计划
循环
为了实现类似循环的语法,需要编写一个解析器,在宏中调用该解析器来解析源表达式。请注意,解析器不处理文本,而是处理内部Lisp数据
在过去(20世纪70年代),Interlisp在所谓的“会话Lisp”中使用了这种语法,这是一种Lisp语法,具有更自然的语言外观。迭代是其中的一部分,迭代思想随后被引入到其他Lisp中(比如Maclisp的循环
,然后被引入到Common Lisp中)
请参阅沃伦·泰尔曼(Warren Teitelmann)上世纪70年代的PDF格式
循环
宏的语法有点复杂,不容易看到各个子语句之间的边界
请参见公共Lisp中的
(loop for i from 0 when (oddp i) collect i)
同:
(loop
for i from 0
when (oddp i)
collect i)
(iter
(for i from 0)
(when (oddp i)
(collect i)))
循环宏存在的一个问题是,诸如FOR
、FROM
、WHEN
和COLLECT
等符号与“COMMON-LISP”包(名称空间)中的符号不同。当我现在使用另一个包(名称空间)在源代码中使用LOOP
时,这将导致在这个源名称空间中出现新的符号。出于这个原因,有些人喜欢写:
(loop
:for i :from 0
:when (oddp i)
:collect i)
在上述代码中,循环
相关符号的标识符位于键中