循环内的函数表现不同

时间:2015-11-07 02:31:32

标签: 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 (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

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

3 个答案:

答案 0 :(得分:2)

代码的缩进和格式化很差。请让您和我们更轻松地阅读代码。

(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-expressions之间缺少空格
  • 错误的缩进级别
  • 代码结构不清楚
  • 不使用内置文档功能
  • 有些行太长了

更好:

(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&Heffock,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的提示。

答案 1 :(得分:1)

您的(+ 1 2)功能实际上输出任何内容。相反,它返回值。

在REPL中,如果您评估表单,例如3,它将始终在最后打印该表单的评估(在本例中为(+ 1 (print 2)))。但是,请考虑print2 3 函数实际上将参数输出到标准输出,然后返回值本身。所以这将显示(在repl上)

2

首先输出(print 2),因为2本身会打印(+ 1 (print 2))。然后,表单(+ 1 2)的评估结果与3try-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

这将打印该{{1}}表单的结果,并返回' nil'。

答案 2 :(得分:1)

这就是你的程序输出和Lisp系统为每次评估所做的输出之间的区别:

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

[3]> (print "3")

"3" 
"3"

接下来,我们在print中对progn进行多次调用。 REPL打印progn表单的值。前三个字符串由代码打印,最后一个字符串打印,因为Lisp REPL打印了值:

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

"1" 
"2" 
"3" 
"3"
相关问题