跳转到内容

Common Lisp/外部库/Iterate

来自维基教科书,开放的书籍,开放的世界

Iterate 提供了一种类似于英语的迭代机制,就像 Common Lisp LOOP 设施一样。这引发了一个问题 - 既然你已经内置了 LOOP,为什么还要使用 Iterate?使用 Iterate 的最佳理由是它具有可扩展性。LOOP 非常静态,但 Iterate 可以扩展到迭代你自己的数据结构,例如。

标准用法

[编辑 | 编辑源代码]

正如你将看到的,Iterate 的语法非常像 LOOP。实际上,将 Iterate 视为带有括号的 LOOP 通常是一个好主意。括号纯粹是美观的。括号背后的主要思想是为文本编辑器提供有关语法应如何格式化的提示,并使其更容易编写扩展。

  • FOR 循环
;; Collect the values from 0 to 9
(iter (for i below 10)
      (collect i))

=> (0 1 2 3 4 5 6 7 8 9)

;; Collect the values from -5 to 10 stepping by PI
(iter (for i from -5 to 10 by pi)
      (collect i)

=> (-5.0d0 -1.8584073464102069d0 1.2831853071795862d0 4.424777960769379d0
 7.5663706143591725d0)

;; Find the number in the file that maximizes the square of itself.
(iter (for number in-file #p"file")
      (finding number maximizing (expt number 2)))

要获取所有 iterate 结构的列表,请使用函数 DISPLAY-ITERATE-CLAUSES。

扩展 Iterates 功能

[编辑 | 编辑源代码]

为了扩展 Iterate,你需要编写一个新的驱动程序。

使用 DEFCLAUSE-SEQUENCE 和 DEFMACRO-DRIVER

[编辑 | 编辑源代码]

DEFMACRO-CLAUSE

[编辑 | 编辑源代码]

Iterate “陷阱”

[编辑 | 编辑源代码]

由 iterate 在 FOR 驱动程序中完成的绑定实际上是通过 SET 完成的。这意味着在你收集一系列闭包时,你必须额外注意这些绑定变量。除非你显式地进行词法绑定,否则闭包将关闭被 iterate 修改的变量。最后,你将得到一个包含所有具有 iterate 退出时绑定的闭包的集合。

不要这样做

(defparameter *closures*
  (iter (for number below 10)
        (collecting (lambda () number)) ))

==> *CLOSURES*

(funcall (first *closures*))

==> 10

这样做

(defparameter *closures*
  (iter (for number below 10)
        (collecting (let ((number number))
                      (lambda () number)) )))

==> *CLOSURES*

(funcall (first *closures*))

==> 0

你应该注意 LOOP 的行为方式相同。

进一步阅读

[编辑 | 编辑源代码]
华夏公益教科书