2

我决定学习编程阅读/做 SICP。

我正在使用 DrRacket 和 http://www.neilvandyke.org/racket-sicp/

我写了一个二十一点程序https://github.com/fnava621/scheme_blackjack。有用。

你能让这个程序更具可读性和简洁吗?

我是不是评论太多了?评论不够?如何让这个程序“更好”?

我也扔掉了手套。你能做一个程序,使用“最优”策略并确定玩家赢庄家的概率(使用 n 个样本大小)吗?我会做同样的事情并比较代码。

感谢阅读/做,费尔南多·纳瓦

4

2 回答 2

3

几点建议:

  1. 避免使用如此多的突变,即set!.
  2. 避免重新定义内置函数,例如length.
  3. 为您的每个函数添加签名和目的声明。请参阅此处以获取解释。
  4. 写测试!尝试使用rackunit,记录在这里
于 2012-02-24T20:01:23.473 回答
2

让我专注于单个功能show-deck。我知道它在做什么,但是可以稍微简化递归。使其更易于阅读可能会稍微降低效率,但我们在这里谈论的是 52 张卡片...... :)

内循环和外循环纠缠在原始代码中。这是一个将它们解开的版本:

(define (show-deck1 first-list second-list)
  (define (outer-loop first-list second-list)
    (cond
      ((null? first-list)
       '())
      (else
       (append (inner-loop (car first-list) second-list)
               (outer-loop (cdr first-list) second-list)))))

  (define (inner-loop x second-list)
    (cond
      ((null? second-list)
       '())
      (else
       (cons (cons x (car second-list))
             (inner-loop x (cdr second-list))))))

  (outer-loop first-list second-list))

我们可以应用一个简化:用这种方式表达的定义,更容易看出map可以用来做inner-loop.

(define (show-deck2 first-list second-list)
  (cond
    ((null? first-list)
     '())
    (else
     (define x (car first-list))
     (append (map (lambda (y) (cons x y)) second-list)
             (show-deck2 (cdr first-list) second-list)))))

这使得更容易看到外部迭代的结构。我们可以map更进一步,将它用于内部和外部循环,并用于(apply append ...)扁平化由嵌套使用引入的子结构map

(define (show-deck3 first-list second-list)
  (apply append 
         (map (lambda (x)
                (map (lambda (y) (cons x y)) second-list))
              first-list)))

您的版本通过巧妙地线程化计算完全避免了(apply append ...)这些东西,但它以牺牲一些可读性为代价。避免(apply append ...)嵌套循环结构并且仍然可以轻松查看嵌套循环结构的一种方法是使用一种foldr方法而不是一种map方法:

(define (foldr f acc l)
  (cond
    ((null? l) acc)
    (else 
     (f (car l)
        (foldr f acc (cdr l))))))

(define (show-deck first-list second-list) 
  (foldr (lambda (x acc)
           (foldr (lambda (y acc)
                    (cons (cons x y) acc))
                  acc
                  second-list))
         '()
         first-list))

这应该与您之前的原始代码相匹配。但是,它将循环性降级为foldr,因此所有这些iter功能都消失在foldr.

就个人而言,如果我用完整的 Racket 编写,我只会用for循环对其进行编码。:) 它看起来像这样:

;; If we're allowed to use full Racket:
(define (show-deck first-list second-list)
  (for*/list ([x first-list]
              [y second-list])
    (cons x y)))
于 2012-02-26T06:33:23.217 回答