Схема программы зависает без исключений - PullRequest
0 голосов
/ 27 января 2012

Хорошо, я учусь на этой схеме в университете, и мы только что получили первое задание.Я испытываю эту странную вещь, хотя.Иногда программа зависает, абсолютно ничего не делая, не предупреждая меня о том, почему это так ...

Выполните следующую процедуру:

(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 = день недели (понедельник, вторник ...) Функция вычисляет разницу в днях между одной и той же датой в y1 и y2 и вычисляет деньнеделю в y2 ...

Эта процедура не работает должным образом.Это на самом деле не даст никакого результата.Однако, если я удаляю последнюю цифру (2) из ​​(define dager-fra-nyttår ...), она работает нормально и выводит день недели на экран вывода (хотя и не правильные даты).

Кто-нибудь знает, почему это так?(с использованием Racket 5.2 на Mac OSX Lion)

1 Ответ

5 голосов
/ 27 января 2012

Звучит так, будто вы застряли в бесконечном цикле.

Я предполагаю, что либо days-between-months, либо days-between-years вызывает себя бесконечно.

Например, days-between-months предполагает, что m1 <= <code>m2. Но если вы называете это с помощью m1> m2, похоже, что оно будет продолжать называть себя «навсегда» - продолжайте пытаться увеличивать m1, пока оно не станет равным m2, но никогда не будет, потому что оно уже больше , (Ну, «никогда», или, по крайней мере, долгое время, пока целое значение не обернется.)

Практически, есть два способа решения этой проблемы.

  • Способ "защитного программирования" заключается в изменении вашего теста if с (= m1 m2) на (<= m1 m2). Многие программисты сделали бы это.

  • В способе Написание твердого кода можно сказать, подождите, проблема в том, что вызывающая сторона передает бессмысленные значения функции: вызывающая сторона должна быть исправлена, скорее чем функция, молча скрывающая ошибку. Если вам нравится такой подход, вы бы добавили assert в такой язык, как C, или здесь вы могли бы сделать что-то вроде (when (> m1 m2) (error)), чтобы преднамеренно вызвать ошибку. Или в Racket, вы можете использовать contract, и он будет жаловаться, если вы попытаетесь нарушить требуемые условия.

После многих лет написания кода я предпочитаю второй подход. Но вы найдете хорошие аргументы в обоих направлениях. Кроме того, это зависит от природы системы, которую вы кодируете, от того, предпочитаете ли вы, чтобы она была "хрупкой" по отношению к сбоям, чтобы вы могли их находить и исправлять, или путалась как можно лучше. Также некоторые люди применяют хрупкий подход в «отладочных» сборках и терпимый к выпущенному продукту.

Наконец, ваш код вызывает пару функций, которые не определены в том, что вы предоставили (например, month-length и year-length), и проблемы могут быть там вместо или в дополнение к тому, что я упомянул.

...