我检查了帖子here有关如何循环文件的信息。我在线检查了几个地方,试图了解在这里再次发布的代码中发生了什么:
(defun get-file (filename)
(with-open-file (stream filename)
(loop for line = (read-line stream nil)
while line
collect line)))
这种语法似乎是如此神秘,而且引用并不容易理解。根据参考文献here"七个中的第四个/作为语法",语法为:
for var [type-spec] = expr1 [then expr2 ]
如果没有 expr2 ,则使用 expr1 。
令我困惑的是什么:
除了工作原理之外我不知道该问什么,我迷失了方向:
while line
collect line
我不知道如何用其他代码替换它。它看起来不像一个列表。我的直觉会告诉我它应该看起来像:
(while line (collect line))
此外,它不同于:
while line collect line
什么是 expr1 :
(read-line stream nil)
while line
collect line)
或
while line
collect line
如果我有更多代码而不是collect line
怎么办?会不会有名单?我看不到结构。
我知道这些不仅仅是一个问题,但可能有一些我想念的东西,让我无法提出一个好问题。
答案 0 :(得分:6)
这是一个循环。多次运行的东西。
基本上,循环有两个部分:
line
以及它发生了什么:在每个循环迭代line
被设置为评估表达式(read-line stream nil)
的结果。这意味着逐行读取行。line
不是nil
,就会将line
的值收集到列表中。因此读取每一行,只要有一行,就将其收集到一个列表中。如果到达输入流的末尾(文件流),(read-line stream nil)
表单返回nil
,则while
看到line
为nil
。 nil
为false,因此循环终止。然后将返回到目前为止收集的行作为结果。
整个loop
表单返回收集的行列表。
此处loop
很方便,因为:
collect ...
子句。<强>背景强>
通常LOOP
是一个宏,它基于70年代早期Interlisp的类似FOR
宏。有一个想法被引入有程序结构可以像普通英语一样使用:用于列表收集项目中的项目。这被称为会话Lisp 。类似的想法例如在Apple的简单脚本语言Applescript中使用。这种风格在Lisp中从未非常流行(虽然还有其他宏使用它),但loop
宏仍然存在,因为它证明是有用的。
答案 1 :(得分:1)
我的直觉会告诉我它应该看起来像:
(线(收集线))
所以你可能会喜欢Shinmera的FOR宏:https://github.com/Shinmera/for
需要知道的最小值是for… over
,其中over是通用的,它适用于许多数据类型。
(for:for ((a over '(1 2 3))
(b over #(a b c))
(c over (for:for ((table as (make-hash-table)))
(setf (gethash (random 10) table) (random 10)) (repeat 3)))
(d over *package*)
(e over *random-state*)
(f over (directory (merge-pathnames "*.*" (user-homedir-pathname))))
(g over (make-string-input-stream "Hi!")))
(print (list a b c d e f g)))