这段 Common Lisp 代码发生了什么?

发布于 2024-12-02 16:34:43 字数 456 浏览 0 评论 0原文

我编写了以下代码来模拟多次滚动六面骰子并计算每一面落地的次数:

(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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

往事随风而去 2024-12-09 16:34:43

continue

This is a result of using a constant list in the initializer:

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

Change that line to:

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

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 keyword collecting which collects the results of each iteration into a list and returns the list as the value of the loop.

画离情绘悲伤 2024-12-09 16:34:43

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

SBCL tells you what's wrong:

* (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

So in essence: Don't call destructive functions (here setf) on constant data.

掩于岁月 2024-12-09 16:34:43

就像上面的帖子一样,编译器将 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)。

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:

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

or wrapped in an (eval-when (compile)) ... )

also

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文