计划程序冻结,没有例外

时间:2012-01-26 21:04:30

标签: scheme racket

好的,我正在大学上学这门课程,我们刚刚完成了第一次任务。我遇到了这个奇怪的事情。有时程序会冻结,绝对不做任何事情而不给我任何形式的警告,为什么这是......

采取以下程序:

(define (calc-week-day y1 m d w y2) ; anta y2 > y1
  (define (days-between-months m1 m2 y)
    (if (= m1 m2)
        0
        (+ (month-length y m1) (days-between-months (+ m1 1) m2 y))))
  (define (days-between-years y1 y2)
    (if (= y1 y2) 
        0
        (+ (year-length y1) (days-between-years (+ y1 1) y2))))
  (define (days-til-months-end d m y)
    (- (month-length y m) d))
  (define (calculate-day day offset)
    (cond ((> day 6) (calculate-day 0 (- offset 1)))
          ((= offset 0) day)
          (else (calculate-day (+ day 1) (- offset 1)))))

  (define dager-til-nyttår (+ (days-between-months m 12 y1)
                              (days-til-months-end d 12 y1) 1))
  (define dager-fra-nyttår (+ (days-between-months 1 m y2) d 2))
  (define dager-mellom-datoer (+ dager-til-nyttår (days-between-years y1 y2)
                                 dager-fra-nyttår))

  (num->day (calculate-day (day->num w) dager-mellom-datoer)))

calc-week-day基本上需要两年时间才能y2 > y1。 m =月,d =天和w =星期几(星期一,星期二......)该函数计算出y1y2中相同日期之间的天数差异,并计算出来y2 ...

中的星期几

此过程无法正常工作。这实际上不会产生任何输出。但是,如果我从(define dager-fra-nyttår ...)删除最后一位数字(2),它就可以正常运行,并在输出屏幕上生成星期几(虽然不是正确的日期)。

任何人都知道这是为什么? (在Mac OSX Lion上使用Racket 5.2)

1 个答案:

答案 0 :(得分:5)

听起来你陷入无限循环。

我的猜测是,days-between-monthsdays-between-years无休止地呼唤着自己。

例如,days-between-months似乎假定m1< = m2。但是如果你用m1>来称呼它m2,看起来它会继续“永远”自称 - 继续尝试增加m1直到它等于m2,但它永远不会,因为它已经更大了。 (好吧,“永远”,或者至少很长一段时间,直到整数值回绕。)

实际上,有两种方法可以解决这个问题。

  • “防御性编程”方式是将if测试从(= m1 m2)更改为(<= m1 m2)。很多程序员都会这样做。

  • 编写固体代码的方式就是说,等等,问题在于调用者将无意义的值传递给函数:调用者应该被修复而不是隐藏错误的功能。如果您喜欢这种方法,则可以使用C语言添加assert,或者在此处执行类似(when (> m1 m2) (error))的操作以故意导致错误。或者在Racket中,您可以使用contract,如果您尝试违反所需条件,它会抱怨。

经过多年编写代码,我更喜欢第二种方法。但你会发现两种方式都有很好的论据。此外,它取决于您编码的系统的性质,您是否希望它对故障“脆弱”,以便您可以找到并修复它们,或尽可能地混淆。还有一些人在“调试”版本中采用了脆弱的方法,对于发布的产品采用了宽容的方法。

最后,您的代码会调用一些未在您提供的内容中定义的函数(例如month-lengthyear-length),而问题可能代替或除了我提到的。