对于var =`语法的常见LISP`循环感到困惑

Mak*_*nix 2 loops common-lisp

我在这里检查了如何循环文件的帖子.我在网上检查了几个地方,试图了解在这里发布的代码中发生了什么:

(defun get-file (filename)
  (with-open-file (stream filename)
    (loop for line = (read-line stream nil)
          while line
          collect line)))
Run Code Online (Sandbox Code Playgroud)

这种语法似乎是如此神秘,而且引用并不容易理解.根据这里的引用"七个中的第四个/作为语法",语法是:

for var [type-spec] = expr1 [then expr2 ]

如果没有expr2,则使用expr1.

令我困惑的是什么:

除了如何工作之外我不知道该问什么,我迷失了方向:

      while line
      collect line
Run Code Online (Sandbox Code Playgroud)

我不知道如何用其他代码替换它.它看起来不像一个列表.我的直觉会告诉我它应该看起来像:

(while line (collect line))
Run Code Online (Sandbox Code Playgroud)

此外,不是同样如下:

while line collect line
Run Code Online (Sandbox Code Playgroud)

什么是expr1:

(read-line stream nil)
              while line
              collect line)
Run Code Online (Sandbox Code Playgroud)

要么

      while line
      collect line
Run Code Online (Sandbox Code Playgroud)

如果我有更多代码而不是collect line?会不会有名单?我没有看到结构.

我知道这些不仅仅是一个问题,但可能有一些我想念的大事,阻止我提出一个好问题.

Rai*_*wig 6

这是一个循环.多次运行的东西.

基本上循环有两个部分:

  1. 第一部分定义了一个变量line以及它发生了什么:在每个循环中迭代line被设置为评估表达式的结果(read-line stream nil).这意味着逐行读取行.
  2. 第二部分是每次迭代运行的子句.这部分说:只要变量line没有nil收集line到列表中的值.

因此,每行都被读取,只要有一行,就将其收集到一个列表中.如果到达输入流的末尾(这是一个文件流),(read-line stream nil)表单返回nil,while看到的linenil.nil是假的,因此循环终止.然后将返回到目前为止收集的行作为结果.

整个loop表单返回收集的行列表.

loop很方便,因为:

  • 它有条件地收集一个值
  • 我们不需要给结果列表一个变量名,因为只有一个累积:单个collect ...子句.
  • 结果列表以正确的顺序返回:第一个收集的项是返回列表中的第一个元素

背景

通常LOOP是一个宏,它基于FOR70年代早期Interlisp 的类似宏.有一个想法被引入有程序结构可以像普通英语一样使用:对于列表收集项目中的项目.这被称为会话Lisp.类似的想法例如在Apple的简单脚本语言Applescript中使用.这种风格在Lisp中从未如此受欢迎(虽然还有其他宏使用它),但loop宏仍然存在,因为它证明是有用的.