T 是常量,不能作为变量使用
T is a constant, may not be used as a variable
我正在为编码挑战编写通用的 lisp 代码,这是一个角色扮演游戏式的谜题,您需要计算战士造成的总杀伤力。因为我对普通的 lisp 很陌生,所以我的代码可能很糟糕。请不要发布一般常见的 lisp 编码提示,除非它们与错误相关。我计划在错误修复后将此代码发布到 codereview
代码 运行 在 tick
内部(底部)条件 when (> overkill-damage 0)
为真之前都很好。我正在使用 GNU Clisp 2.49 运行 这段代码。
(defun timer (initialization-time interval)
(list :init initialization-time :interval interval :ready nil :time-passed 0))
(defun tick-timer (timer)
(let ((newtime (1+ (getf timer :time-passed))))
(when (and (not (getf timer :ready)) (>= newtime (getf timer :init)))
(setf (getf timer :ready) t))
(setf (getf timer :time-passed) newtime)))
(defun timer-ready? (timer)
(and
(getf timer :ready)
(= 0 (mod (getf timer :time-passed) (getf timer :interval)))))
(defun weapon (damage timer)
(list :damage damage :timer timer))
(defun weapon-attack (weapon)
(tick-timer (getf weapon :timer))
(if (timer-ready? (getf weapon :timer))
(getf weapon :damage)
0))
(defun attack (character)
(reduce #'(lambda (total weapon) (+ (weapon-attack weapon) total)) (getf character :weapons) :initial-value 0))
(defun attack-monster (monster damage)
(- monster damage))
(defun calculate-overkill-damage (health)
(if (> health 0)
0
(abs health)))
(defparameter *warrior* `(:weapons ,(list (weapon 35 (timer 0 4)))))
(defparameter *mage* `(:weapons ,(list (weapon 80 (timer 2 8)))))
(defparameter *rogue* `(:weapons ,(list (weapon 20 (timer 0 3))
(weapon 30 (timer 0 4)))))
(defparameter *monsters* '(300 600 850 900 1100 3500))
(defparameter *current-monster* 0)
(defparameter *overkill* 0)
(defparameter *game-over* nil)
; I assume, for now, that when a monster dies, they will miss the rest of their attacks
(defun tick ()
(sleep .1)
(let* ((monster (nth *current-monster* *monsters*))
(new-health (attack-monster monster (attack *warrior*)))
(overkill-damage (calculate-overkill-damage new-health)))
(format t "Attacking~%-------~%Attacking monster ~a, which has ~a health." *current-monster* monster)
(format t "~%Dealt ~a overkill damage!" overkill-damage)
(when (> overkill-damage 0)
(do (format t "Dealt ~a overkill damage!" overkill-damage)
(setf *overkill* (+ *overkill* overkill-damage))
(format t "Total overkill damage is now ~a" *overkill*)
(setf *current-monster* (1+ *current-monster*))
(format t "Moving to next monster, ~a" *current-monster*)
(when (= *current-monster* (1- (length *monsters*)))
(setf *game-over* t))))
(let* ((new-health (attack-monster monster (attack *mage*)))
(new-health (attack-monster monster (attack *rogue*))))
(setf (nth *current-monster* *monsters*) new-health)
(format t "~%Monster is now at ~a health~%" (nth *current-monster* *monsters*)))))
(loop for x from 1 until (equal *game-over* t)
do (tick))
最重要的部分是代码底部的 tick
函数。当这段代码得到 运行 时,我得到错误 *** - LET: T is a constant, may not be used as a variable
.
这是执行时打印的内容:
TRUNCATED LOTS OF POINTLESS MESSAGES...
-------
Attacking monster 0, which has 10 health.
Dealt 0 overkill damage!
Monster is now at 10 health
Attacking
-------
Attacking monster 0, which has 10 health.
Dealt 25 overkill damage!
*** - LET: T is a constant, may not be used as a variable
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead.
ABORT :R2 Abort main loop
Break 1 [18]> :w
<1/172> #<SPECIAL-OPERATOR LET>
[170] EVAL frame for form
(LET (FORMAT T "Dealt ~a overkill damage!" OVERKILL-DAMAGE)
(TAGBODY #:LOOP-5923 (IF SETF (GO #:END-5924))
(FORMAT T "Total overkill damage is now ~a" *OVERKILL*)
(SETQ *CURRENT-MONSTER* (1+ *CURRENT-MONSTER*))
(FORMAT T "Moving to next monster, ~a" *CURRENT-MONSTER*)
(WHEN (= *CURRENT-MONSTER* (1- (LENGTH *MONSTERS*))) (SETQ *GAME-OVER* T))
(PSETQ) (GO #:LOOP-5923) #:END-5924
(RETURN-FROM NIL (PROGN *OVERKILL* (+ *OVERKILL* OVERKILL-DAMAGE)))))
Break 1 [18]>
那个 :w
命令显示的代码根本不存在,我真的不明白那里发生了什么。
即使我在 tick
上调用 macroexpand,代码 (LET (FORMAT T "Dealt ~a overkill damage!" OVERKILL-DAMAGE)......
也不会出现在任何地方。
有人知道这是怎么回事吗?或者,如果您有任何 CLISP 调试技巧可以帮助我查明错误,请告诉我!
do
的第一个参数定义循环的局部变量,就像 let
一样;您将其用作 body.
的开头
嗯,我不明白代码应该做什么,但你的错误来自 DO
:http://www.lispworks.com/documentation/HyperSpec/Body/m_do_do.htm
如文档所述,这是一个循环,其第一个参数是变量列表:
(do (format t "Dealt ~a overkill damage!" overkill-damage)
这尝试使用 format
、t
、"Dealt ~a overkill damage!"
和 overkill-damage
作为变量。
如果您只想在 when
的正文中使用多个表单,则无需执行任何特殊操作。 when
开箱即用:
(when (> overkill-damage 0)
(format t "Dealt ~a overkill damage!" overkill-damage)
(setf *overkill* (+ *overkill* overkill-damage))
(format t "Total overkill damage is now ~a" *overkill*)
...)
DO
是 Common Lisp 中的一个宏。它是 Lisp 中较旧的控制结构之一,如 DOLIST
和 DOTIMES
.
由于是宏,调试起来可能比较困难。特别是当 DO
宏本身不进行任何语法检查时。
为了在 Lisp 中调试,我们可以使用编译器和解释器。首先让我们使用编译器:
[1]> (defun test () (do (format t "hello world") (read)))
TEST
[2]> (compile 'test)
** - Continuable Error
in TEST : Illegal syntax in LET/LET*: "hello world"
编译器给出关于非法语法的错误信息。所以有语法错误,但是并没有说清楚是从哪里来的。由于代码中没有LET
或LET*
,所以一定是来自于某种语法转换->宏。 DEFUN
和 DO
是宏。
(macro-function 'do) -> #<COMPILED-FUNCTION DO>
下一步是看DO
形式的宏展开:
[4]> (macroexpand-1 '(do (format t "hello world") (read)))
(BLOCK NIL
(LET (FORMAT T "hello world")
(TAGBODY #:LOOP-3239 (IF READ (GO #:END-3240)) (PSETQ) (GO #:LOOP-3239) #:END-3240
(RETURN-FROM NIL (PROGN))))) ;
T
在上面的表格中我们看到 LET
并且我们可以看到绑定是错误的。所以 DO
形式可能是错误的。
现在是检查 do
语法的最佳时机:请参阅 DO 的 HyperSpec 条目。通常这应该足够清楚,可以找到语法错误。
我们也可以使用 CLISP 解释器并逐步完成示例:
[5]> (step (test))
step 1 --> (TEST)
Step 1 [6]> step
step 2 --> (BLOCK NIL (LET (FORMAT T "hello world") (TAGBODY #:LOOP-3210 # # ...)))
Step 2 [7]> step
step 3 --> (LET (FORMAT T "hello world") (TAGBODY #:LOOP-3210 (IF READ #) (PSETQ) ...))
Step 3 [8]> step
*** - LET: T is a constant, may not be used as a variable
基本上我们看到每一步都完成了代码转换。
由于 Common Lisp 有很多实现,其中一些具有更好的错误消息。例如 SBCL:
* (defun test () (do (format t "hello world") (read)))
; in: DEFUN TEST
; (DO (FORMAT
; T
; "hello world")
; (READ))
;
; caught ERROR:
; during macroexpansion of
; (DO (FORMAT
; T
; "hello world")
; (READ)).
; Use *BREAK-ON-SIGNALS* to intercept.
;
; "hello world" is an illegal form for a DO varlist.
;
; compilation unit finished
; caught 1 ERROR condition
那就更好了。
我正在为编码挑战编写通用的 lisp 代码,这是一个角色扮演游戏式的谜题,您需要计算战士造成的总杀伤力。因为我对普通的 lisp 很陌生,所以我的代码可能很糟糕。请不要发布一般常见的 lisp 编码提示,除非它们与错误相关。我计划在错误修复后将此代码发布到 codereview
代码 运行 在 tick
内部(底部)条件 when (> overkill-damage 0)
为真之前都很好。我正在使用 GNU Clisp 2.49 运行 这段代码。
(defun timer (initialization-time interval)
(list :init initialization-time :interval interval :ready nil :time-passed 0))
(defun tick-timer (timer)
(let ((newtime (1+ (getf timer :time-passed))))
(when (and (not (getf timer :ready)) (>= newtime (getf timer :init)))
(setf (getf timer :ready) t))
(setf (getf timer :time-passed) newtime)))
(defun timer-ready? (timer)
(and
(getf timer :ready)
(= 0 (mod (getf timer :time-passed) (getf timer :interval)))))
(defun weapon (damage timer)
(list :damage damage :timer timer))
(defun weapon-attack (weapon)
(tick-timer (getf weapon :timer))
(if (timer-ready? (getf weapon :timer))
(getf weapon :damage)
0))
(defun attack (character)
(reduce #'(lambda (total weapon) (+ (weapon-attack weapon) total)) (getf character :weapons) :initial-value 0))
(defun attack-monster (monster damage)
(- monster damage))
(defun calculate-overkill-damage (health)
(if (> health 0)
0
(abs health)))
(defparameter *warrior* `(:weapons ,(list (weapon 35 (timer 0 4)))))
(defparameter *mage* `(:weapons ,(list (weapon 80 (timer 2 8)))))
(defparameter *rogue* `(:weapons ,(list (weapon 20 (timer 0 3))
(weapon 30 (timer 0 4)))))
(defparameter *monsters* '(300 600 850 900 1100 3500))
(defparameter *current-monster* 0)
(defparameter *overkill* 0)
(defparameter *game-over* nil)
; I assume, for now, that when a monster dies, they will miss the rest of their attacks
(defun tick ()
(sleep .1)
(let* ((monster (nth *current-monster* *monsters*))
(new-health (attack-monster monster (attack *warrior*)))
(overkill-damage (calculate-overkill-damage new-health)))
(format t "Attacking~%-------~%Attacking monster ~a, which has ~a health." *current-monster* monster)
(format t "~%Dealt ~a overkill damage!" overkill-damage)
(when (> overkill-damage 0)
(do (format t "Dealt ~a overkill damage!" overkill-damage)
(setf *overkill* (+ *overkill* overkill-damage))
(format t "Total overkill damage is now ~a" *overkill*)
(setf *current-monster* (1+ *current-monster*))
(format t "Moving to next monster, ~a" *current-monster*)
(when (= *current-monster* (1- (length *monsters*)))
(setf *game-over* t))))
(let* ((new-health (attack-monster monster (attack *mage*)))
(new-health (attack-monster monster (attack *rogue*))))
(setf (nth *current-monster* *monsters*) new-health)
(format t "~%Monster is now at ~a health~%" (nth *current-monster* *monsters*)))))
(loop for x from 1 until (equal *game-over* t)
do (tick))
最重要的部分是代码底部的 tick
函数。当这段代码得到 运行 时,我得到错误 *** - LET: T is a constant, may not be used as a variable
.
这是执行时打印的内容:
TRUNCATED LOTS OF POINTLESS MESSAGES...
-------
Attacking monster 0, which has 10 health.
Dealt 0 overkill damage!
Monster is now at 10 health
Attacking
-------
Attacking monster 0, which has 10 health.
Dealt 25 overkill damage!
*** - LET: T is a constant, may not be used as a variable
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead.
ABORT :R2 Abort main loop
Break 1 [18]> :w
<1/172> #<SPECIAL-OPERATOR LET>
[170] EVAL frame for form
(LET (FORMAT T "Dealt ~a overkill damage!" OVERKILL-DAMAGE)
(TAGBODY #:LOOP-5923 (IF SETF (GO #:END-5924))
(FORMAT T "Total overkill damage is now ~a" *OVERKILL*)
(SETQ *CURRENT-MONSTER* (1+ *CURRENT-MONSTER*))
(FORMAT T "Moving to next monster, ~a" *CURRENT-MONSTER*)
(WHEN (= *CURRENT-MONSTER* (1- (LENGTH *MONSTERS*))) (SETQ *GAME-OVER* T))
(PSETQ) (GO #:LOOP-5923) #:END-5924
(RETURN-FROM NIL (PROGN *OVERKILL* (+ *OVERKILL* OVERKILL-DAMAGE)))))
Break 1 [18]>
那个 :w
命令显示的代码根本不存在,我真的不明白那里发生了什么。
即使我在 tick
上调用 macroexpand,代码 (LET (FORMAT T "Dealt ~a overkill damage!" OVERKILL-DAMAGE)......
也不会出现在任何地方。
有人知道这是怎么回事吗?或者,如果您有任何 CLISP 调试技巧可以帮助我查明错误,请告诉我!
do
的第一个参数定义循环的局部变量,就像 let
一样;您将其用作 body.
嗯,我不明白代码应该做什么,但你的错误来自 DO
:http://www.lispworks.com/documentation/HyperSpec/Body/m_do_do.htm
如文档所述,这是一个循环,其第一个参数是变量列表:
(do (format t "Dealt ~a overkill damage!" overkill-damage)
这尝试使用 format
、t
、"Dealt ~a overkill damage!"
和 overkill-damage
作为变量。
如果您只想在 when
的正文中使用多个表单,则无需执行任何特殊操作。 when
开箱即用:
(when (> overkill-damage 0)
(format t "Dealt ~a overkill damage!" overkill-damage)
(setf *overkill* (+ *overkill* overkill-damage))
(format t "Total overkill damage is now ~a" *overkill*)
...)
DO
是 Common Lisp 中的一个宏。它是 Lisp 中较旧的控制结构之一,如 DOLIST
和 DOTIMES
.
由于是宏,调试起来可能比较困难。特别是当 DO
宏本身不进行任何语法检查时。
为了在 Lisp 中调试,我们可以使用编译器和解释器。首先让我们使用编译器:
[1]> (defun test () (do (format t "hello world") (read)))
TEST
[2]> (compile 'test)
** - Continuable Error
in TEST : Illegal syntax in LET/LET*: "hello world"
编译器给出关于非法语法的错误信息。所以有语法错误,但是并没有说清楚是从哪里来的。由于代码中没有LET
或LET*
,所以一定是来自于某种语法转换->宏。 DEFUN
和 DO
是宏。
(macro-function 'do) -> #<COMPILED-FUNCTION DO>
下一步是看DO
形式的宏展开:
[4]> (macroexpand-1 '(do (format t "hello world") (read)))
(BLOCK NIL
(LET (FORMAT T "hello world")
(TAGBODY #:LOOP-3239 (IF READ (GO #:END-3240)) (PSETQ) (GO #:LOOP-3239) #:END-3240
(RETURN-FROM NIL (PROGN))))) ;
T
在上面的表格中我们看到 LET
并且我们可以看到绑定是错误的。所以 DO
形式可能是错误的。
现在是检查 do
语法的最佳时机:请参阅 DO 的 HyperSpec 条目。通常这应该足够清楚,可以找到语法错误。
我们也可以使用 CLISP 解释器并逐步完成示例:
[5]> (step (test))
step 1 --> (TEST)
Step 1 [6]> step
step 2 --> (BLOCK NIL (LET (FORMAT T "hello world") (TAGBODY #:LOOP-3210 # # ...)))
Step 2 [7]> step
step 3 --> (LET (FORMAT T "hello world") (TAGBODY #:LOOP-3210 (IF READ #) (PSETQ) ...))
Step 3 [8]> step
*** - LET: T is a constant, may not be used as a variable
基本上我们看到每一步都完成了代码转换。
由于 Common Lisp 有很多实现,其中一些具有更好的错误消息。例如 SBCL:
* (defun test () (do (format t "hello world") (read)))
; in: DEFUN TEST
; (DO (FORMAT
; T
; "hello world")
; (READ))
;
; caught ERROR:
; during macroexpansion of
; (DO (FORMAT
; T
; "hello world")
; (READ)).
; Use *BREAK-ON-SIGNALS* to intercept.
;
; "hello world" is an illegal form for a DO varlist.
;
; compilation unit finished
; caught 1 ERROR condition
那就更好了。