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

时间:2018-01-09 21:16:49

标签: loops common-lisp

我检查了帖子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怎么办?会不会有名单?我看不到结构。

我知道这些不仅仅是一个问题,但可能有一些我想念的东西,让我无法提出一个好问题。

2 个答案:

答案 0 :(得分:6)

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

基本上,循环有两个部分:

  1. 第一部分定义了变量line以及它发生了什么:在每个循环迭代line被设置为评估表达式(read-line stream nil)的结果。这意味着逐行读取行。
  2. 第二部分是每次迭代运行的子句。这部分说明:只要变量line不是nil,就会将line的值收集到列表中。
  3. 因此读取每一行,只要有一行,就将其收集到一个列表中。如果到达输入流的末尾(文件流),(read-line stream nil)表单返回nil,则while看到linenilnil为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)))