Loops 为什么有一个=sign-in循环宏用于从文件中读取行?
我一直在试图弄清楚如何用公共lisp处理读取文件,因为答案看起来总是完全一样的,我不理解lisp的循环宏语法或其他相关内容。 在下面的代码中(从您看到的代码中有一个“loop for line=(read line)…”我不明白numeric=符号在测试中的含义。为什么是数字等号?read line返回什么数字?是nil和t数字吗Loops 为什么有一个=sign-in循环宏用于从文件中读取行?,loops,syntax,common-lisp,Loops,Syntax,Common Lisp,我一直在试图弄清楚如何用公共lisp处理读取文件,因为答案看起来总是完全一样的,我不理解lisp的循环宏语法或其他相关内容。 在下面的代码中(从您看到的代码中有一个“loop for line=(read line)…”我不明白numeric=符号在测试中的含义。为什么是数字等号?read line返回什么数字?是nil和t数字吗 (defun get-file (filename) (with-open-file (stream filename) (loop for line =
(defun get-file (filename)
(with-open-file (stream filename)
(loop for line = (read-line stream nil)
while line
collect line)))
我总是直觉地认为“(行中的循环(读行)…”会起作用,因为读行返回一个字符串,但我猜它实际上返回nil的值,而字符串只是它放在终端上的一些垃圾…但我不明白。
有人对这种疯狂有见解或方法吗?(
开始一个Lisp表单
循环
这是循环
宏
对于行=(读取行流nil)
我们定义一个局部变量line
,在每次循环
迭代中,它将被设置为(读取行流nil)
的结果
(读取行流nil)
以字符串形式返回行,或者nil
如果流处于eof
而行
每次迭代时检查此项,并在变量line
不是nil
如果是nil
,则退出循环
,并返回结果
收集行
对于每次迭代,将变量行
的内容收集到一个列表中,然后作为结果返回该列表
)
Lisp表单的结尾循环宏在普通Lisp中是唯一的,也就是说,它是唯一定义自己的完整小语法的宏。这种语法更像是在Algol、Pascal、C或Python语言规范中遇到的语法。循环宏对其进行解析,并将其转换为更标准的Lisp表单 因此,
循环的主体是一系列语句。在您的示例中,有三个分别以for
、with
和collect
开头
所有这些都是初学者困惑的根源
例如,您可以看到标记=,然后在手册中查找它。您可以找到一个用于测试数值相等性的函数。但是在循环宏中,For
语句中,它是循环宏使用的小语法的一部分
FOR子句将安排将词法变量line
绑定到每次循环调用(read line stream nil)
的结果
这里的另一个混乱来源是READ-LINE
函数接受一个流以及一些可选参数。这里只提供了一个,即nil。该参数控制READ-LINE
到达文件末尾时发生的情况。nil
抑制它自然引发的错误,并要求它执行返回值NIL
这似乎有点奇怪,因为虽然大多数时候读取行返回一个字符串
,但此可选参数允许它返回两种类型:string
或null
while
子句处理这个问题,当我们得到类型为null
的值,即nil值时终止循环
collect
子句很有趣,因为它为循环的作者做了大量的工作。它神奇地在循环中创建状态,将各行累积到一个列表中,然后在循环退出时返回该列表。循环宏的典型实现将非常有效地完成这项工作
在学习这门语言的过程中,经常会有这样的反应:“wtf?这看起来不像Lisp?!?”虽然这很公平,但是循环非常有用,有很多代码都在使用它
还有其他选择,例如iterate
(这不是标准的一部分)和series
(这是一个后期添加)。但两者都有点奇怪/聪明。循环
宏是一个用于迭代的DSL。它的语法通常被认为不清晰,但我已经习惯了。=
与数值无关,只是一个赋值运算符,它将读取行
的返回值绑定到行
。我想我这只是一个习惯的问题,或者尝试一个简单的“do”循环。除了Rainer的答案之外,你还可以找到一个很好的介绍@MartinBuchmann你的第一条评论实际上是我在页面上的问题的唯一正确答案。它消除了根本的误解。循环中的=关键字与普通Lisp中的=函数具有不同的语义。我误解了,以为它们是相同的(或相似的)。我希望我可以标记一条注释作为答案!(我回到这个问题,因为它仍然没有标记为已回答)系列没有添加到标准中,即使它在CLtL2中。