2013-05-21 43 views
5

我正在使用基於CL的音樂作品的可視化編程環境。我試圖創建一個函數,當給定說3個元素(1 2 3)將返回1,2,3,1,2,3等,每次評估時的一個數字。這本書Common Lisp一個溫柔的介紹,簡單地提到可以使用尖銳的平等符號創建循環列表,但沒有詳細說明如何使用它們。請記住,我可以使用專門爲此設計的對象在程序中插入實際的Lisp代碼。Common Lisp中的圓形列表

+3

另請參見[Lisp循環列表](http://stackoverflow.com/q/15536​​564/1281433)和[Sharpsign等符號閱讀器宏示例](http://stackoverflow.com/q/12649290/1281433 )。 –

回答

8

Sharpsign Equal-Sign表示法中,它被寫爲#0=(1 2 3 . #0#)

下面是它創建從給定的參數,例如列表的功能:

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

然後調用​​將返回你想要的循環鏈表。只需使用carcdr即可遍歷無限元素。

如果你真的想要一個迭代函數,它沒有參數和返回的下一個項目爲每個呼叫,這裏是你將如何做到這一點:

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

您可以使用PROG1而不是LET。 –

+2

@ThomasBartscher謝謝!現已實施。 (其實我看着Rainer的回答,看起來'pop'和我之後做的事情是一樣的,當Schemer試圖寫CL的時候會發生什麼......-)) –

+1

呵呵,我沒有想到這一點。太好了! –

10
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 
+0

謝謝你,這是非常有幫助的。 –

+0

是否有任何書籍或網站建議您幫助我瞭解更多關於此類事物的信息? –

+1

在循環表達式上有一個放在Lambda上的部分:http://letoverlambda.com/index.cl/guest/chap4.html#sec_5 –

0

下面是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功能來添加,刪除和訪問項目。我在想,我給出的內容足以顯示你爲這種循環列表定義的任何函數所需做的事情。這似乎是我在聽衆中工作的。