计划 - 二十一点计划(SICP)/学习计划

时间:2012-02-24 16:36:17

标签: scheme racket sicp

我决定学习阅读/做SICP。

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

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

你能让这个程序更易读和简洁吗?

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

我也放下了手套。你能制作一个使用“最佳”策略的程序,并确定玩家赢得经销商的概率(使用n个样本大小)吗?我会做同样的事情并比较代码。

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

2 个答案:

答案 0 :(得分:3)

一些建议:

  1. 避免使用如此多的变异,即set!
  2. 避免重新定义内置函数,例如length
  3. 为每个功能添加签名和目的语句。有关说明,请参阅here
  4. 写测试!尝试使用rackunit,记录here

答案 1 :(得分: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)))