循环内的函数表现不同

Functions inside a loop behaves differently

所以我有一个循环来重复我做的关于 dota 的小文字游戏,但是当函数 'play' 在循环中被调用时它不会 return 我的结果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)

ALACRITY wwe
GOOD-JOB

但是如果我调用函数 'loop-play' 我会得到以下结果 o/p:

Break 3 [7]> (loop-play 2)    
SUN-STRIKE eee    
ALACRITY wwe
TORNADO qww
NIL

有人可以向我解释为什么会这样吗? 编辑:随意更改标题,我真的不知道该放什么。

您的 try-for-combo 函数实际上 输出 任何东西。相反,它 returns 值。

在 REPL 中,如果你评估一个表单,比如 (+ 1 2),它总是会在最后打印该表单的评估(在本例中,3)。但是,请考虑 (+ 1 (print 2))print 函数实际上将参数输出到标准输出,然后 return 输出值本身。所以这将显示(在 repl 上)

2
3

首先输出2,因为(print 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 表单和 return 'nil' 的结果。

这只是您的程序输出与 Lisp 系统对每次评估的输出之间的差异:

print 打印一些东西(一个换行符,然后是它的参数)和 returns 一个值。该值由 REPL 打印。因此我们看到输出两次:

[3]> (print "3")

"3" 
"3"

接下来我们在 progn 中多次调用 printprogn 形式的值由 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 的 Hemlock,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 代码,为您节省大量工作。

manual indentation有提示。