2011-09-01 17 views
10

Pisałem następujące bitowego kodu do symulacji walcowania sześć jednostronne umiera kilka razy i liczenia, ile razy każda strona wylądowaliśmy:Co się dzieje z tym wspólnym kodem Lisp?

(defun dice (num) 
    (let ((myList '(0 0 0 0 0 0))) 
    (progn (format t "~a" myList) 
      (loop for i from 1 to num do 
       (let ((myRand (random 6))) 
        (setf (nth myRand myList) (+ 1 (nth myRand myList))))) 
      (format t "~a" myList)))) 

Funkcja działa świetnie po raz pierwszy, ja to nazywam , ale przy kolejnych wywołaniach zmienna myList zaczyna się od wartości, jaką miał pod koniec ostatniego połączenia, zamiast być inicjalizowanym z powrotem do wszystkich zer, tak jak myślę, że powinno się zdarzyć z oświadczeniem let. Dlaczego to się dzieje?

+1

FYI, większość ludzi piszących często lisp używa tych nazw, takich jak 'my-list' zamiast' myList'. Ponadto, nie sądzę, że potrzebujesz tego prognowania, ponieważ "treść niech jest domyślnym progiem" http://www.lispworks.com/documentation/HyperSpec/Body/s_let_l.htm (to jest jak prognowanie już tam jest). –

Odpowiedz

13

Wynika to z użyciem stałej listy w inicjalizatorze:

(let ((myList '(0 0 0 0 0 0))) 

Zmiana tej linii do:

(let ((myList (list 0 0 0 0 0 0))) 

i będzie zachowywać się zgodnie z oczekiwaniami. W pierwszym wierszu występuje tylko jeden raz (ponieważ jest to lista stała), ale wywołanie list wymusza alokację za każdym razem, gdy funkcja zostanie wprowadzona.

edytuj: Może to być pomocne, szczególnie pod koniec. Successful Lisp

Odpowiedź na pytanie this może być również pomocna.

Używa słowa kluczowego loopcollecting, które gromadzi wyniki każdej iteracji na liście i zwraca listę jako wartość loop.

+0

Dzięki Andrew i Michael. To wystarczyło. Jestem nowy w Lisp (to chyba oczywiste) i sprawdzę tekst, z którym się łączyłeś. – Dustin

+0

Nie ma problemu, Lisp to bardzo fajny język do nauki :) Jak zauważył Michael, SBCL może być bardzo pomocny, bardzo agresywnie ostrzega przed potencjalnie niebezpiecznymi operacjami. – asm

+1

Ponadto, zazwyczaj, używając tablicy zamiast listy, gdy zamierzasz ją wielokrotnie indeksować i nie często rozwijać, jest to Dobra Rzecz. – Vatine

8

SBCL mówi, co się stało:

* (defun dice (num) 
    (let ((myList '(0 0 0 0 0 0))) 
    (progn (format t "~a" myList) 
      (loop for i from 1 to num do 
       (let ((myRand (random 6))) 
        (setf (nth myRand myList) (+ 1 (nth myRand myList))))) 
      (format t "~a" myList)))) 
; in: DEFUN DICE 
;  (SETF (NTH MYRAND MYLIST) (+ 1 (NTH MYRAND MYLIST))) 
; ==> 
; (SB-KERNEL:%SETNTH MYRAND MYLIST (+ 1 (NTH MYRAND MYLIST))) 
; 
; caught WARNING: 
; Destructive function SB-KERNEL:%SETNTH called on constant data. 
; See also: 
;  The ANSI Standard, Special Operator QUOTE 
;  The ANSI Standard, Section 3.2.2.3 
; 
; compilation unit finished 
; caught 1 WARNING condition 

DICE 

Tak w istocie: Nie wywoływać funkcje destrukcyjne (tutaj setf) na stałych danych.

-1

podobnie jak post powyżej, kompilator przydziela 0 jako stałą przestrzeń. Kiedyś znać kilka sztuczek na to, jeden będzie sprawiają, że makro takie:

`',(list 0 0 0 0 0) 
=> 
?? (I forget and don't have the other machine on to check) 

lub owinięte w (eval-when (compile)) ...)

także

(list 0 0 0 0 0) 
=> 
    #.(list 0 0 0 0) 

Nie wiem, czy to nadal działa (lub kiedykolwiek pracował). Są także pewne makra lub makra kompilatora, które mogłyby pomóc w utrzymaniu stałej wielkości alokacji, ale zmiennej danych. Nie pamiętam więcej z mojej głowy.

Pamiętaj, aby użyć wypełnienia (np. Bzero w c).

Powiązane problemy