Lisp 循环中的函数的行为不同

Lisp 循环中的函数的行为不同,lisp,common-lisp,read-eval-print-loop,clisp,Lisp,Common Lisp,Read Eval Print Loop,Clisp,所以我有一个循环来重复我做的关于dota的小文本游戏,但是当在循环中调用函数“play”时,它不会返回我的cond函数的结果,它只接受一个输入,然后进入下一个循环 ;;;;learn the invoker combo's (defparameter *invoker-combo* '((cold-snap (3 0 0) 'QQQ);all of the possible invoker combo's (ghost-walk

所以我有一个循环来重复我做的关于dota的小文本游戏,但是当在循环中调用函数“play”时,它不会返回我的cond函数的结果,它只接受一个输入,然后进入下一个循环

;;;;learn the invoker combo's
(defparameter *invoker-combo* '((cold-snap  (3 0 0) 'QQQ);all of the possible invoker combo's
                                (ghost-walk (2 1 0) 'QQW)
                                (Ice-Wall (2 0 1) 'QQE)
                                (EMP (0 3 0) 'WWW)
                                (Tornado (1 2 0) 'QWW)
                                (Alacrity (0 2 1) 'WWE)
                                (Sun-Strike (0 0 3) 'EEE)
                                (Forge-Spirit (1 0 2) 'QEE)
                                (Chaos-Meteor (0 1 2) 'WEE)
                                (Deafening-Blast (1 1 1) 'QWE)))
(defun rand-combo (invoker-combo);returns a random combo
    (nth (random (length invoker-combo))invoker-combo))

(defun count-letters (input);converts the keyboard strokes into numbers to be compared as it doesn't matter what order they are in, just that there is the correct quantity of them e.g QQE could also be written QEQ.
    (append
        (list (count #\Q input)
              (count #\W input)
              (count #\E input))))

(defun try-for-combo (rand-combo);takes i-p and compares it with the value for the random combo
    (print(car rand-combo))
    (let* ((i-p (string-upcase(read-line)))
            (try (count-letters i-p)))
            (cond ((equal try (cadr rand-combo))'Good-job)
                  ((equal i-p "END")(list 'Thanks 'for 'playing))
                  (t (list i-p 'was 'wrong 'correct 'is (caddr(assoc (car rand-combo)*invoker-combo*)))))))

(defun play ()
    (try-for-combo (rand-combo *invoker-combo*)))

(defun loop-play (x)
    (loop for i from 0 to x
        :do (play)))
如果我调用函数“play”,我会得到以下o/p:

FORGE-SPIRIT asdf
("ASDF" WAS WRONG CORRECT IS 'QEE)
Break 3 [7]> (loop-play 2)    
SUN-STRIKE eee    
ALACRITY wwe
TORNADO qww
NIL

但如果我调用函数“循环播放”,我会得到以下o/p:

FORGE-SPIRIT asdf
("ASDF" WAS WRONG CORRECT IS 'QEE)
Break 3 [7]> (loop-play 2)    
SUN-STRIKE eee    
ALACRITY wwe
TORNADO qww
NIL
有人能给我解释一下为什么会这样吗?
编辑:请随意更改标题,我真的不知道该放什么。

您的
try for combo
函数实际上没有输出任何内容。相反,它返回值

在REPL中,如果对表单求值,如
(+1 2)
,它将始终在末尾打印该表单的求值(在本例中为
3
)。但是,请考虑<代码>(+ 1(打印2))< /代码>。
print
函数实际上将参数输出到标准输出,然后返回值本身。因此,这将显示(在repl上)

首先输出
2
,因为
(打印2)
本身打印
2
。然后,表单
(+1(print 2))
的计算结果与
(+1 2)
3
相同

在您的情况下,
try-for-combo
函数应该如下所示:

(defun try-for-combo (rand-combo)
  (print (car rand-combo))
  (let* ((i-p (string-upcase(read-line)))
         (try (count-letters i-p)))
    (print
     (cond
       ((equal try (cadr rand-combo)) 'Good-job)
       ((equal i-p "END") (list 'Thanks 'for 'playing))
       (t (list i-p 'was 'wrong 'correct 'is (caddr(assoc (car rand-combo) *invoker-combo*))))))
    nil))

这将打印该
cond
表单的结果,并返回“nil”

您的
try for combo
函数实际上没有输出任何内容。相反,它返回值

在REPL中,如果对表单求值,如
(+1 2)
,它将始终在末尾打印该表单的求值(在本例中为
3
)。但是,请考虑<代码>(+ 1(打印2))< /代码>。
print
函数实际上将参数输出到标准输出,然后返回值本身。因此,这将显示(在repl上)

首先输出
2
,因为
(打印2)
本身打印
2
。然后,表单
(+1(print 2))
的计算结果与
(+1 2)
3
相同

在您的情况下,
try-for-combo
函数应该如下所示:

(defun try-for-combo (rand-combo)
  (print (car rand-combo))
  (let* ((i-p (string-upcase(read-line)))
         (try (count-letters i-p)))
    (print
     (cond
       ((equal try (cadr rand-combo)) 'Good-job)
       ((equal i-p "END") (list 'Thanks 'for 'playing))
       (t (list i-p 'was 'wrong 'correct 'is (caddr(assoc (car rand-combo) *invoker-combo*))))))
    nil))

这将打印该
cond
表单的结果,并返回“nil”

这只是您的程序的输出与Lisp系统在每次求值时的输出之间的差异:

print
打印某些内容(一个换行符,然后是它的参数)并返回一个值。该值由REPL打印。因此,我们看到了两次输出:

[3]> (print "3")

"3" 
"3"
接下来,我们在一个
progn
中调用几个
print
progn
表单的值由REPL打印。前三个字符串由代码打印,最后一个字符串由于Lisp REPL打印值而打印:

[4]> (progn (print "1") (print "2") (print "3"))

"1" 
"2" 
"3" 
"3"

这只是程序输出与Lisp系统每次求值输出之间的差异:

print
打印某些内容(一个换行符,然后是它的参数)并返回一个值。该值由REPL打印。因此,我们看到了两次输出:

[3]> (print "3")

"3" 
"3"
接下来,我们在一个
progn
中调用几个
print
progn
表单的值由REPL打印。前三个字符串由代码打印,最后一个字符串由于Lisp REPL打印值而打印:

[4]> (progn (print "1") (print "2") (print "3"))

"1" 
"2" 
"3" 
"3"

代码的缩进和格式很差。请让您和我们更容易阅读代码

(defun try-for-combo (rand-combo);takes i-p and compares it with the value for the random combo
    (print(car rand-combo))
    (let* ((i-p (string-upcase(read-line)))
            (try (count-letters i-p)))
            (cond ((equal try (cadr rand-combo))'Good-job)  ; wrong indent level
                  ((equal i-p "END")(list 'Thanks 'for 'playing))
                  (t (list i-p 'was 'wrong 'correct 'is (caddr(assoc (car rand-combo)*invoker-combo*)))))))
  • s表达式之间缺少空格
  • 错误的缩进级别
  • 守则的结构不清楚
  • 不使用内置文档功能
  • 有些线路太长了
更好:

(defun try-for-combo (rand-combo)
  "takes i-p and compares it with the value for the random combo" ; built in doc
  (print (car rand-combo))
  (let* ((i-p (string-upcase (read-line)))
         (try (count-letters i-p)))
    (cond ((equal try (cadr rand-combo))                          ; indentation
           'Good-job)
          ((equal i-p "END")
           (list 'Thanks 'for 'playing))
          (t
           (list i-p 'was 'wrong 'correct 'is                     ; several lines
                 (caddr (assoc (car rand-combo)
                               *invoker-combo*)))))))
我建议使用一个真正理解Lisp格式的编辑器。像GNU Emacs/SLIME,Clozure CL的铁杉,LispWorks的编辑

如果您对格式不确定,也可以要求Lisp进行设置。Clisp不太擅长格式化,但类似SBCL或CCL的功能可以:

* (let ((*print-case* :downcase))
  (pprint '(defun try-for-combo (rand-combo)
 (print (car rand-combo))
                    (let* ((i-p (string-upcase (read-line)))
 (try (count-letters i-p)))
                            (cond ((equal try (cadr rand-combo))
 'Good-job) ((equal i-p "END")
                              (list 'Thanks 'for 'playing))
 (t (list i-p 'was 'wrong 'correct 'is
                                      (caddr (assoc (car rand-combo)
 *invoker-combo*)))))))))
您可以得到格式良好的代码:

(defun try-for-combo (rand-combo)
  (print (car rand-combo))
  (let* ((i-p (string-upcase (read-line))) (try (count-letters i-p)))
    (cond ((equal try (cadr rand-combo)) 'good-job)
          ((equal i-p "END") (list 'thanks 'for 'playing))
          (t
           (list i-p 'was 'wrong 'correct 'is
                 (caddr (assoc (car rand-combo) *invoker-combo*)))))))
编辑器自动缩进Lisp代码可以节省大量工作


有提示。

代码的缩进和格式很差。请让您和我们更容易阅读代码

(defun try-for-combo (rand-combo);takes i-p and compares it with the value for the random combo
    (print(car rand-combo))
    (let* ((i-p (string-upcase(read-line)))
            (try (count-letters i-p)))
            (cond ((equal try (cadr rand-combo))'Good-job)  ; wrong indent level
                  ((equal i-p "END")(list 'Thanks 'for 'playing))
                  (t (list i-p 'was 'wrong 'correct 'is (caddr(assoc (car rand-combo)*invoker-combo*)))))))
  • s表达式之间缺少空格
  • 错误的缩进级别
  • 守则的结构不清楚
  • 不使用内置文档功能
  • 有些线路太长了
更好:

(defun try-for-combo (rand-combo)
  "takes i-p and compares it with the value for the random combo" ; built in doc
  (print (car rand-combo))
  (let* ((i-p (string-upcase (read-line)))
         (try (count-letters i-p)))
    (cond ((equal try (cadr rand-combo))                          ; indentation
           'Good-job)
          ((equal i-p "END")
           (list 'Thanks 'for 'playing))
          (t
           (list i-p 'was 'wrong 'correct 'is                     ; several lines
                 (caddr (assoc (car rand-combo)
                               *invoker-combo*)))))))
我建议使用一个真正理解Lisp格式的编辑器。像GNU Emacs/SLIME,Clozure CL的铁杉,LispWorks的编辑

如果您对格式不确定,也可以要求Lisp进行设置。Clisp不太擅长格式化,但类似SBCL或CCL的功能可以:

* (let ((*print-case* :downcase))
  (pprint '(defun try-for-combo (rand-combo)
 (print (car rand-combo))
                    (let* ((i-p (string-upcase (read-line)))
 (try (count-letters i-p)))
                            (cond ((equal try (cadr rand-combo))
 'Good-job) ((equal i-p "END")
                              (list 'Thanks 'for 'playing))
 (t (list i-p 'was 'wrong 'correct 'is
                                      (caddr (assoc (car rand-combo)
 *invoker-combo*)))))))))
您可以得到格式良好的代码:

(defun try-for-combo (rand-combo)
  (print (car rand-combo))
  (let* ((i-p (string-upcase (read-line))) (try (count-letters i-p)))
    (cond ((equal try (cadr rand-combo)) 'good-job)
          ((equal i-p "END") (list 'thanks 'for 'playing))
          (t
           (list i-p 'was 'wrong 'correct 'is
                 (caddr (assoc (car rand-combo) *invoker-combo*)))))))
编辑器自动缩进Lisp代码可以节省大量工作


有一些提示。

您可能希望更好地缩进和格式化代码。如果您看到类似
BREAK 3[7]>
的提示,则您的Lisp交互在调试器中。从调试器中取出它。使用命令
help
获取可用命令的帮助<代码>退出将Lisp恢复到顶层。好的,谢谢。你有没有关于如何正确格式化我的代码的链接,因为这是我在读的书中的做法,我也发布了关于它的问题,每个人都对它充满敌意,所以我不介意。我看了我正在读的书,书中只有一些小东西,在美学上或实践上没有什么不同,Floofk考虑使用RAND COMPO选项中的调用器组合变量,并默认为调用组合。还使用一个调用程序组合列表,删除第三列,因为它是多余的。可以使用函数将列表表示形式转换为“人类可读”的表示形式