球拍代码返回void

时间:2016-03-21 04:45:14

标签: racket void

(define (solver row col board boolboard) ;solve the game
  (if (equal? row 9)      
  board           
  (if (equal? (get-value boolboard row col) #t)          
      (begin            
        (for ([ite '(1 2 3 4 5 6 7 8 9)]) ;true              
          (when (equal? (check-available row col ite board) #t) ;should be careful here                
            (begin                  
              (let ([new-board (set-value board row col ite)])
                (if (equal? col 8)
                    (solver (+ 1 row) 0 new-board boolboard)
                    (solver row (+ 1 col) new-board boolboard)))
              )          
          )
        ))      
      (if (and (equal? col 8) (equal? row 8)) ;false
          board
          (if (equal? col 8)

              (solver (+ 1 row) 0 board boolboard)

              (solver row (+ 1 col) board boolboard)

          )))
  )
  )

这是soduku解算器。我已经检查了解算器最终到达了(如果(等于?第9行)所以它得到了电路板。但是函数仍然返回#。我不知道为什么它没有返回电路板。

任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:3)

修复这些类型的错误的一般规则:

如果它返回了您不期望的内容(此处为#<void>),那么请查找函数中可能返回的内容。您确定基本案例返回您期望的内容,但您还必须检查其他案例。

下一个案例中有一个begin,其中包含for。无论在任何迭代中返回的正文表达式是什么,for形式总是返回#<void>

因此,您可以回复#<void>for表单在每次迭代时计算循环体,但忽略返回值。

因此,for几乎不是你想要的。通常情况下,for/listfor/orfor/fold这样的表单会更有用。在这种情况下,for/first看起来可能就是您的意思。

如果你盲目翻译,

(for/first ([ite '(1 2 3 4 5 6 7 8 9)])
  (when (equal? (check-available row col ite board) #t)
    (let ([new-board (set-value board row col ite)])
      (if (equal? col 8)
          (solver (+ 1 row) 0 new-board boolboard)
          (solver row (+ 1 col) new-board boolboard)))))

然后这仍然无效,因为它仍会在很多时候返回#<void>,因为when形式在条件为假时返回#<void>for/first形式并不神奇。它没有看到when表单失败或使用该信息转到下一个子句。要使for/first检查条件并继续执行下一条,如果它是假的,请在#:when之后使用[ite ...]子句。

(for/first ([ite '(1 2 3 4 5 6 7 8 9)]
            #:when (equal? (check-available row col ite board) #t))
  (let ([new-board (set-value board row col ite)])
    (if (equal? col 8)
        (solver (+ 1 row) 0 new-board boolboard)
        (solver row (+ 1 col) new-board boolboard))))

for/first表单将评估#:when条件为真的第一次迭代的正文,然后返回。

但是,如果任何迭代的#:when条件永远不为真,则for/first表单将返回false,这将导致solver函数返回false。

但这意味着for/first表单中的递归调用可能返回false。如果发生这种情况,该怎么办?您可能想要进入循环的下一次迭代。为此,您可以使用for/or,它类似于for/first,但如果正文返回false,它将继续进行下一次迭代。

(for/or ([ite '(1 2 3 4 5 6 7 8 9)]
         #:when (equal? (check-available row col ite board) #t))
  (let ([new-board (set-value board row col ite)])
    (if (equal? col 8)
        (solver (+ 1 row) 0 new-board boolboard)
        (solver row (+ 1 col) new-board boolboard))))

这样,如果填写一个数字并不会产生一个解决方案,并且返回false,则可以尝试下一个数字。

这解决了有关它返回#<void>的问题。如果您的代码存在更多问题,则应该提出另一个问题。