1

出于教育目的,我正在尝试以实用的方式在球拍中实现猜我的号码游戏。我的问题是我必须停止函数并出现错误,如(error "YOU GUESSED!"). 错误函数是我可以在球拍文档中找到的。有没有一种无错误的方法来阻止这个条件?

注意:我读到了stop-when,但我还不想进入 big-bang。

(define guess-my-number (lambda ()
  (letrec ([my-number (random 100)]
           [choices-left 7]
           [game (lambda (choices-left)
                (if (> choices-left 0)
                    (let ([user-guess (read)])
                      (cond [(> user-guess my-number) (display "That was too high!")]
                            [(< user-guess my-number) (display "That was too small!")]
                            [(= user-guess my-number) (error "YOU GUESSED!")])
                    (game (- choices-left 1)))
                    (display "Here ends the game!!")))])
    (game choices-left))))
4

2 回答 2

2

克里斯的回答是完美的。这确实是一个注释——除了它有点长而且你不能在这里的注释中做代码块。

编写代码的方式是了解 Racket 在“低级别”如何工作的好方法,并且是在 Scheme 中编写代码的一种非常传统的方式。

Scheme 中的另一种传统方式是使用几个特性:

  • 定义函数的简写方式。

  • 一个有名let的,使用典型的名字loop

那个版本:

(define (guess-my-number-v2)
  (let ([number (random 100)])
    (let loop ([guesses-left 7])
      (cond [(> guesses-left 0)
             (define user-guess (read))
             (cond [(> user-guess number)
                    (display "That was too high!")
                    (loop (sub1 guesses-left))]
                   [(< user-guess number)
                    (display "That was too low!")
                    (loop (sub1 guesses-left))]
                   [else (display "YOU GUESSED!")])]
            [else
             (displayln "Here ends the game!!")]))))

有趣的是,它扩展为与您的第一个版本几乎完全相同的东西。

(let loop (guesses-left 7]) ...)表单本质上定义了一个名为 的函数loop,与您原来的名为 的函数非常相似game。(实际上你也可以说(let game ([guesses-left 7]) ...)。)

一个好处是它没有那么深的缩进并且不会离开屏幕的右侧。

最后,这是一个更“球拍-y”的版本,更多地使用define

(define (guess-my-number-v3)
  (define number (random 100))
  (define (guess guesses-left)
    (cond [(> guesses-left 0)
           (define user-guess (read))
           (cond [(> user-guess number)
                  (display "That was too high!")
                  (guess (sub1 guesses-left))]
                 [(< user-guess number)
                  (display "That was too low!")
                  (guess (sub1 guesses-left))]
                 [else (display "YOU GUESSED!")])]
          [else
           (displayln "Here ends the game!!")]))
  (guess 7))

尽管这更像是一种“现代”球拍风格,但它本质上并不是“更好”。它也扩展为与原始版本几乎完全相同的东西。事实上,大多数 Racket 程序员都会发现所有 3 种风格都很容易理解。

无论如何,所有 3 个版本都通过递归调用一个函数来“循环”,就像你已经在做的那样。“终止循环”的方法很简单......不要再次调用该函数。这是克里斯回答的重点。

于 2013-11-12T00:11:58.503 回答
1

是的。在要重新(game (- choices-left 1))循环的cond分支内进行递归:

(define guess-my-number (lambda ()
  (letrec ([my-number (random 100)]
           [choices-left 7]
           [game (lambda (choices-left)
                   (if (> choices-left 0)
                       (let ([user-guess (read)])
                         (cond [(> user-guess my-number) (display "That was too high!")
                                                         (game (- choices-left 1))]
                               [(< user-guess my-number) (display "That was too small!")
                                                         (game (- choices-left 1))]
                               [(= user-guess my-number) (display "YOU GUESSED!")]))
                       (display "Here ends the game!!")))])
    (game choices-left))))
于 2013-11-11T22:37:24.897 回答