我决定学习一种Lisp语言,我发现了一种非常奇怪和新的语法。必须的第一个程序,也使用所有的基础,是数字猜测游戏。
error更干净的方式退出循环吗?define null和set!可以吗?#lang racket
(define NUM 12)
(define TRIES 6)
(define CORRECT "Correct! Well guessed!")
(define TOO_LOW "... Too Low ...")
(define TOO_HIGH "... Too high ...")
(define (num_message player_num)
(if (= player_num NUM)
CORRECT
(if (> player_num NUM)
TOO_HIGH
TOO_LOW
)
)
)
(define (number-guessing-game)
(define out null)
(for ([i (range TRIES)])
(set! out (num_message (read)))
(print out)
(when (equal? out CORRECT)
(print "You won")
(error "Exiting")
)
)
(print "Too many attempts")
)
(number-guessing-game)发布于 2015-07-23 12:13:15
胜利不应被视为错误。如果想要从for-循环中退出,请使用#:break。但在类似Lisp的语言中,for和set!并不是真正的惯用语言。相反,更常见的是使用符合函数式编程范例的递归和let。
在num_message中,您可以使用cond而不是嵌套的ifs。
我对使用字符串比较来检测获胜条件并不满意:number-guessing-game函数需要知道从num_message得到什么祝贺消息。您已经通过定义一些字符串常量来解决这个问题,这使它们比人们预期的更重要。
如果num_message不修复NUM,而number-guessing-game不修复NUM和TRIES,就更优雅了。
如果number-guessing-game函数被分解,它将更加清晰,因为它实际上做了两件事情:只做一次猜测,和有条件地重复。
print调用可能应该是displayln,这样也可以编写一个尾换行符。
通常,标识符中的单词是separated-by-hyphens而不是下划线。结束括号没有自己的行。
#lang racket
(define NUM 12)
(define TRIES 6)
(define (num-message delta)
(cond [(< delta 0) "... Too low ..."]
[(> delta 0) "... Too high ..."]
[else "Correct! Well guessed!"]))
(define (guess-number target)
(let ([delta (- (read) target)])
(displayln (num-message delta))
(zero? delta)))
(define (number-guessing-game target tries)
(cond [(zero? tries) (displayln "Too many attempts")]
[(guess-number target) (displayln "You won")]
[else (number-guessing-game target (- tries 1))]))
(number-guessing-game NUM TRIES)发布于 2015-07-28 16:24:46
num-message是迈向模块化的一步。for的思想指向了一个非常有用和惯用的抽象,通常出现在Lisp/racket/Lisp程序中: streams。将猜测视为要处理的流是有用的。需要改进的
num-message中的控制流混在一起。代码演示了一些不同的也许更好,也许更糟技术。
关键的抽象是三个流:
将常量声明为函数可以在不影响主控制流的情况下重新定义它们的行为。提供变量参数性允许对主循环的语义进行实验,而不依赖于函数的实现或基于参数数的分派。
#lang racket
#| Data Types |#
(struct game-message (start win lose too-high too-low))
#| User Interaction |#
(define messages
(game-message "Please make your first guess: "
"\nWinner Winner Chicken Dinner!\n"
"\nAll your guesses are belong to us :(\n"
"\nYour guess is too high. Please Guess again: "
"\nYour guess is too low. Please Guess again: "))
(define (get-target . args)
12)
(define (get-guesses . args)
6)
(define (get-guess . args)
(read))
(define (inform-user message)
(display message))函数make-game以目标和多个猜测作为输入,并返回在clock流上迭代的函数,从猜测流中进行猜测,并在消息流上输出消息。
#| Constructor |#
(define (make-game target guesses)
(define (game clock)
(let ((guess (get-guess)))
(cond
[(equal? guess target)
(inform-user (game-message-win messages))]
[(= clock guesses)
(inform-user (game-message-lose messages))]
[(< guess target)
(inform-user (game-message-too-low messages))
(game (add1 clock))]
[(> guess target)
(inform-user (game-message-too-high messages))
(game (add1 clock))])))
game)一个名为“主”具有特殊地位的子模块在命令行被racket调用时:它将自动执行。
游戏执行从调用make-game作为闭锁返回的函数开始。
#| Play game |#
(module* main #f
(game-message-start messages)
((make-game (get-target)(get-guesses)) 1))请注意,这是运行在操作系统外壳,而不是球拍REPL。
$ racket number-game.rkt
"Please make your first guess: "
5
Your guess is too low. Please Guess again: 6
Your guess is too low. Please Guess again: 9
Your guess is too low. Please Guess again: 99
Your guess is too high. Please Guess again: 55
Your guess is too high. Please Guess again: 18
All your guesses are belong to us :(https://codereview.stackexchange.com/questions/87075
复制相似问题