scheme ::合同违规:递归程序

时间:2016-11-22 18:38:41

标签: recursion scheme lisp racket

我需要编写一个以列表作为参数的方案程序,该程序定义获得的分数,玩家A分数和玩家B分数。该功能应根据分数确定谁是赢家:

例如,这是我在下面使用的分数列表列表:

(define scores '(
                 (5 . (5 . 3)) ; points awarded = (car (car scores)) 5; player A score = cadr (car scores)) 5; player B score (cddr (car scores)) 3;
                 (5 . (6 . 2))
                 (5 . (8 . 4))
                 (5 . (5 . 1))))

所以只是澄清一下,打破列表中的第一个列表:

5 =获得分数(car (car scores)) ;

A =玩家A得分(cadr (car scores)) ;(第一个元素为5,第二个元素为6,等等)

B =玩家B得分(cddr (car scores)) ;(第一个元素为3,第二个元素为2,等等)

问题是我已经做了一个递归函数,它在递归的第一次迭代中爆炸。但我不明白为什么?

#lang scheme

(define (game-winner scores)  
  (define A 0)
  (define B 0)
  (cond
    ((empty? scores) '()))
  (if ( > (cadr (car scores)) (cddr (car scores)) )
      (+ A (car (car scores)))
      (+ B (car (car scores))))
  (game-winner (cdr scores)))

输出:

car: contract violation
  expected: pair?
  given: ()

令我困惑的部分是,当我模拟在递归的第一次迭代中运行并获得函数应该时所具有的值时,我得到正确的值:

;first loop through function

    (car (car scores))  ; 5
    (cadr (car scores)) ; 5
    (cddr (car scores)) ; 3

;second loop (1st recursive call)

    (cadr (car (cdr scores))) ; 6
    (cddr (car (cdr scores))) ; 2

所以,如果我不明白它为什么会爆炸?它的工作方式与递归前的第一次调用相同。但我显然错过了一些东西。有什么想法吗?

P.S。 如果我只是返回A或B而不是递归调用,我得到0:

(define (game-winner scores)  
  (define A 0)
  (define B 0)
  (cond
    ((empty? scores) '()))
  (if ( > (cadr (car scores)) (cddr (car scores)) )
      (+ A (car (car scores)))
      (+ B (car (car scores))))
  A)

输出: 0

为什么第一次通话后A的值(应该是5)在我输出A时没有显示? A仅在if循环的范围内?如果是这样,我如何让它存在于该范围之外?

基于@Sylwester的反馈我按程序修改为:

#lang scheme

(define (game-winner scores)  
  (define A 0)
  (define B 0)
  (cond
    ((empty? scores) '())
    (( > (cadr (car scores)) (cddr (car scores)))    
     (cons (+ A (car (car scores))) (game-winner (cdr scores))))
    (cons (+ B (car (car scores))) (game-winner (cdr scores)))))

输出:

(5 5 5 5)

所以我觉得我越来越近了。但是我需要能够为A或B添加这些,并输出获胜者(A或B)。我如何在此基础上进行构建以实现这一目标?

1 个答案:

答案 0 :(得分:2)

你的代码有很多死代码,无论结果如何都不会被使用,最后表达式会(cdr scores),无论它是否为空。

(define (game-winner scores)  
  ;; Two constants that never change from 0
  (define A 0)
  (define B 0)

  ;; Dead code. Werther it's '() or #<undefined>
  (cond
    ((empty? scores) '()))

  ;; Dead code. Becomes (+ 0 (car scores)) but never used
  (if ( > (cadr (car scores)) (cddr (car scores)) )
      (+ A (car (car scores)))  ; + never mutates A
      (+ B (car (car scores)))) ; + never mutates B

  ;; Infinite recursion. Happens no matter what is the outcome of the dead code
  (game-winner (cdr scores)))

因此,当您编写condif时,它应该处理所有发生的事情,以便它是最后一个表达式:

(define (game-winner scores)
  ; local defines
  (define some-var some-expression)
  ...

  ; one expression, the result of this is the result of the procedure.
  (if (empty? scores)
      '()
      (if ....)))

修改

以下是使用参数累积分数的递归示例,最后确定谁得分最高:

(define (game-winner scores)
  (let loop ((scores scores) (a 0) (b 0))
    (if (empty? scores)
        (cond ((> a b) 'A)
              ((< a b) 'B)
              (else 'TIE)))
        (loop (cdr scores)
              (+ a (cadar scores))
              (+ b (cddar scores))))))

(game-winner scores)
; ==> A