我编写了下面的代码来模拟滚动一个六边模具的次数,并计算每一个边落了多少次:
(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))))这个函数在我第一次调用它时工作得很好,但是在随后的调用中,变量myList从上次调用结束时的值开始,而不是像我认为应该在let语句中发生的那样被初始化回所有的零。这一切为什么要发生?
发布于 2011-09-01 20:46:38
这是在初始化器中使用常量列表的结果:
(let ((myList '(0 0 0 0 0 0)))将这一行改为:
(let ((myList (list 0 0 0 0 0 0)))它会像你期望的那样。第一行只导致一次分配(因为它是一个常量列表),但是通过调用list,您将强制在每次输入函数时进行分配。
编辑:这可能是有帮助的,特别是在最后。成功Lisp
这问题的答案也可能是有帮助的。
这使用loop关键字collecting,它将每个迭代的结果收集到一个列表中,并将列表作为loop的值返回。
发布于 2011-09-01 20:44:59
SBCL告诉您出了什么问题:
* (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因此,本质上:不要对常量数据调用破坏性函数(此处为setf)。
发布于 2011-12-24 08:56:27
与上面的post一样,编译器将0分配为常量空间。我以前知道这方面的一些窍门,其中之一就是把它变成这样的宏:
`',(list 0 0 0 0 0)
=>
?? (I forget and don't have the other machine on to check)或者包装在(eval-when (compile)) ... )中
也是
(list 0 0 0 0 0)
=>
#.(list 0 0 0 0)我不知道这是否仍然有效(或者曾经起过作用)。这些也是一些实现宏或编译器宏,可以帮助保持分配大小不变,但数据变量。别再想起我的头了。
记住使用fill (如c中的bzero )。
https://stackoverflow.com/questions/7276234
复制相似问题