2012-01-26 37 views
0

好吧,我在这所大学参加这个计划课程,我们刚刚完成了第一个任务。虽然我遇到了这个奇怪的事情。有时程序会冻结,什么都不做,没有给我任何形式的警告,为什么这是...计划程序冻结,没有例外

采取以下步骤:

(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

你有任何助手功能的测试用例吗?你知道你的辅助函数是否有效吗?这不像起初看起来似乎是一个轻浮的问题。我不相信计算日会在所有预期条件下终止。例如,如果你通过一天大于6的偏移量和一个等于零的偏移量,它将不会终止。顺便说一下,如果您使用的是DrRacket,请尝试按下“停止”按钮。它应该通常告诉你你的程序在哪里计算。可能会提示发生无限循环的位置。 – dyoo

+0

这个帮手是由proffessor编写的,已经使用了至少几年,所以我认为他们工作的广告,即使没有提供测试用例... –

+0

“帮助函数”,我的意思是所有内部定义的函数在calc-week-day中。据推测,你的教授没有写这些,否则还有什么是你要做的? :)另外,当你在追踪看起来像无限循环的东西时寻求帮助时,请提供示例输入,以便希望提供帮助的人员可以复制您的场景。你周日输入的是什么输入数据,如果程序运行正常,你期望看到什么? – dyoo

回答

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),并且问题可能在那里,而不是我提到的。

+0

嗯,听起来似乎合理。阅读这段代码并不像阅读Javascipt或Java那样简单,因为我也习惯了,这可能是我自己没有发现它的原因......当我从工作中回来看看它是否是答案时我会测试它我在找。在此期间,我会给你一个很好的答案=) –

+1

一旦你的大脑重新自我解读,它会变得更容易。不久之后,您可以在阅读“{}”语言和“()”语言之间进行切换,就像阅读英语和挪威语之间轻松翻阅一样。 :) –