2013-05-21 18 views
5

Pracuję wykorzystując wizualne środowisko programistyczne do kompozycji muzycznej opartej na CL. Próbuję utworzyć funkcję, która po powiedzeniu, że 3 elementy (1 2 3) zwrócą 1, 2, 3, 1, 2, 3 itd., Jedną liczbę w czasie za każdym razem, gdy jest oceniany. Książka Common Lisp a Gentle Wstęp, krótko wspomina, że ​​możliwe jest tworzenie okrągłych list przy użyciu ostro-równomiernej notacji, ale nie wchodzi w szczegóły, jak z nich korzystać. Należy pamiętać, że mogę wstawić rzeczywisty kod Lisp w programie przy użyciu specjalnie do tego celu zaprojektowanego obiektu.Okólnik w Common Lisp

+3

Zobacz także [Lisp cyclic lists] (http://stackoverflow.com/q/15536564/1281433) i [Przykład makra czytnika książek Sharpsign Equal-Sign] (http://stackoverflow.com/q/12649290/1281433). –

Odpowiedz

8

W notacji Sharpsign Equal-Sign jest to napisane jako #0=(1 2 3 . #0#).

Oto funkcja, która stwarza taką listę z podanych argumentów:

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

Następnie, nazywając (circular 1 2 3) zwróci listę okrągły chciałeś. Po prostu użyj car i cdr do iteracji elementów w nieskończoność.

A jeśli naprawdę chcesz funkcję iterator, która pobiera żadnych argumentów i zwraca następną pozycję dla każdego połączenia, oto jak można to zrobić:

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

Możesz użyć PROG1 zamiast LET. –

+2

@ThomasBartscher Dzięki! Jest teraz zaimplementowany. (Właściwie to popatrzyłem na odpowiedź Rainera i wydaje mi się, że 'pop' robi to samo, co ja po.) Tak dzieje się, gdy Schemat próbuje napisać CL. ;-)) –

+1

Huh, nie myślałem o tym. Miły! –

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#) 

Przykład:

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 

także:

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

Z dodanym bitem 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

Dziękuję, że to bardzo pomocne. –

+0

Czy są jakieś książki lub witryny, które sugerujesz, które pomogłyby mi dowiedzieć się więcej o tego typu rzeczach? –

+1

Istnieje sekcja w Let Over Lambda w wyrażeniach cyklicznych: http://letoverlambda.com/index.cl/guest/chap4.html#sec_5 –

0

Oto pomysł opracowany na okrągłą listę w 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") 

Nie zapewniam funkcji defun do dodawania, usuwania i uzyskiwania dostępu do przedmiotów. Myślę, że to, co podałem, wystarczy, aby pokazać, co trzeba zrobić w dowolnej funkcji zdefiniowanej dla tego rodzaju listy okrężnej. Wydawało mi się, że działa w słuchaczu.