【问题标题】:Circular list in Common LispCommon Lisp 中的循环列表
【发布时间】:2013-05-16 17:08:20
【问题描述】:

我正在使用基于 CL 的音乐创作可视化编程环境。我正在尝试创建一个函数,当给定 3 个元素 (1 2 3) 时,它将返回 1、2、3、1、2、3 等,每次评估时都会返回一个数字。 Common Lisp a Gentle Introduction 一书简要提到可以使用尖等符号创建循环列表,但没有详细说明如何使用它们。 请记住,我可以使用专门为此设计的对象在程序中插入实际的 Lisp 代码。

【问题讨论】:

标签: lisp common-lisp circular-list


【解决方案1】:
CL-USER 3 > (defun circular (items)
              (setf (cdr (last items)) items)
              items)
CIRCULAR

CL-USER 4 > (setf *print-circle* t)
T

CL-USER 5 > (circular (list 1 2 3))
#1=(1 2 3 . #1#)

例子:

CL-USER 16 > (setf c1 (circular (list 1 2 3)))
#1=(1 2 3 . #1#)

CL-USER 17 > (pop c1)
1

CL-USER 18 > (pop c1)
2

CL-USER 19 > (pop c1)
3

CL-USER 20 > (pop c1)
1

还有:

CL-USER 6 > '#1=(1 2 3 . #1#)
#1=(1 2 3 . #1#)

加上一点CLOS:

(defclass circular ()
  ((items :initarg :items)))

(defmethod initialize-instance :after ((c circular) &rest initargs)
  (setf (slot-value c 'items) (circular (slot-value c 'items))))

(defmethod next-item ((c circular))
  (prog1 (first (slot-value c 'items))
    (setf (slot-value c 'items)
          (rest (slot-value c 'items)))))

CL-USER 7 > (setf circ1 (make-instance 'circular :items (list 1 2 3)))
#<CIRCULAR 40200017CB>

CL-USER 8 > (next-item circ1)
1

CL-USER 9 > (next-item circ1)
2

CL-USER 10 > (next-item circ1)
3

CL-USER 11 > (next-item circ1)
1

CL-USER 12 > (next-item circ1)
2

【讨论】:

  • 谢谢,这很有帮助。
  • 有没有你推荐的书籍或网站可以帮助我更多地了解这类事情?
  • Let Over Lambda 中有一节是关于循环表达式的:letoverlambda.com/index.cl/guest/chap4.html#sec_5
  • circular的定义中不需要返回items,因为setf无论如何都会返回。
  • @tsikov:是的,但我希望它在源代码中更清晰,而不是依赖于读者的知识。
【解决方案2】:

Sharpsign Equal-Sign 表示法中,它写为#0=(1 2 3 . #0#)

这是一个从给定参数创建这样一个列表的函数:

(defun circular (first &rest rest)
  (let ((items (cons first rest)))
    (setf (cdr (last items)) items)))

然后,调用(circular 1 2 3) 将返回您想要的循环列表。只需使用carcdr 无限循环遍历元素。

如果你真的想要一个不带参数并为每次调用返回下一项的迭代器函数,你可以这样做:

(defun make-iter (list)
  (lambda ()
    (pop list)))

【讨论】:

  • 你可以用 PROG1 代替 LET。
  • @ThomasBartscher 谢谢!现在已经实施了。 (实际上,我查看了 Rainer 的答案,似乎 pop 与我所追求的相同。这就是 Schemer 尝试编写 CL 时发生的情况。;-))
  • 呃,我没想到。不错!
  • 为了记录:该符号在 HyperSpec 中被称为 Sharpsign Equal-Sign(第 2.4.8.15 节)。
  • @ssice 谢谢!编辑了帖子。
【解决方案3】:

这是在 Lisp 中为循环列表制定的一个想法。

;;; Showing structure of the list
;;; (next prev is-end val)

; create items
setf L-0 (L-1 L-3 t "L-0 sentry")  ; this will be the sentry item so know where to stop
setf L-1 (L-2 L-0 nil "L-1")
setf L-2 (L-3 L-1 nil "L-2")
setf L-3 (L-0 L-2 nil "L-3")

; how to access L-2 from L-0
eval (first (eval (first L-0)))

; result: (L-3 L-1 NIL "L-2")

我没有提供 defun 函数来添加、删除和访问项目。我认为我给出的内容足以说明您在为这种循环列表定义的任何函数中需要做什么。在我看来,这在 Listener 中起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 1970-01-01
    • 2016-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 2018-09-23
    相关资源
    最近更新 更多