这段 Common 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))))
该函数在我第一次调用它时效果很好,但在后续调用中变量 myList 开始输出它在最后一次调用结束时的值,而不是像我认为在 let 语句中应该发生的那样被初始化回全零。为什么会出现这种情况?
I've written the following bit of code to simulate rolling a six-sided die a number of times and counting how many times each side landed up:
(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))))
The function works great the first time I call it, but on subsequent calls the variable myList starts out at the value it had at the end of the last call, instead of being initialized back to all zeros like I thought should happen with the let statement. Why does this happen?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
continue
This is a result of using a constant list in the initializer:
Change that line to:
and it will behave as you expect. The first line only results in an allocation once (since it's a constant list), but by calling
list
you force the allocation to occur every time the function is entered.edit:
This may be helpful, especially towards the end. Successful Lisp
The answer to this question may also be helpful.
This uses the
loop
keywordcollecting
which collects the results of each iteration into a list and returns the list as the value of theloop
.SBCL 告诉您出了什么问题:
所以本质上:不要对常量数据调用破坏性函数(此处为
setf
)。SBCL tells you what's wrong:
So in essence: Don't call destructive functions (here
setf
) on constant data.就像上面的帖子一样,编译器将 0 分配为常量空间。我曾经知道一些技巧,其中一个是将其设为一个宏,例如:
或包装在
(eval-when (compile)) ... )
中,
我也不知道这是否仍然有效(或曾经有效)。还有一些实施
宏或编译器宏可以帮助保持分配大小恒定,但数据
多变的。别再在我的脑海里想起了。
记住使用 fill (如 c 中的 bzero)。
like the post above, the compiler allocates the 0 as constant space. I used to know some tricks for this, one would be make it a macro such:
or wrapped in an
(eval-when (compile)) ... )
also
I don't know if this still works (or ever worked). The are also some implentation
macros or compiler macros that could help keep the alloaction size constant but the data
variable. Don't rememeber off the top of my head anymore.
remeber to use fill (like bzero in c).